💻 Tech
Yesterday’s journal talked about using copy
to safely copy the data from a slice to another. We saw that just using the slice command (e.g., data[2:3
]) may cause side effect of unintended change of the original slice. Another way to safely perform a copy is by maxing out the capacity.
But first, let’s revisit a problem. Unlike yesterday’s program, the program below shows that when you append an item to a slice of another slice, you can potentially modify the backing array. To be specific, the 0
and 1
indices of the new slice actually point to the 2
and 3
of the original slice. When you look at the capacity of the new slice that’s printed after it’s created, you’ll see it’s 3. What’s 3? It’s pointing to the same backing array, which is 4
index in the original slice. So, when you append to the new slice, it’s 2
index, but it’s actually overwriting the original value of 4
index. From kamusta
, it becaome MUDOU
. You’ll also notice that both share the same memory 0xc000074090
.
To remediate this, we can use a 3-index-slice that accepts a third parameter which is the capacity. But let’s see another concept first in the demo program 2.
Demo program 1
func main() {
fmt.Println("#####")
fmt.Println("original slice")
greetings := []string{"ola", "nihao", "salut", "oi", "kamusta"}
displaySlice(greetings)
fmt.Println("\n#####")
fmt.Println("slice of slice")
greetings1 := greetings[2:4]
displaySlice(greetings1)
fmt.Println("\n#####")
fmt.Println("side effect: modified new slice index")
greetings1 = append(greetings1, "MUDOU")
fmt.Println("original slice")
displaySlice(greetings)
fmt.Println("slice of slice")
displaySlice(greetings1)
}
func displaySlice(s []string) {
fmt.Printf("len:%v, cap:%v\n", len(s), cap(s))
for i, v := range s {
fmt.Printf("%v %v %v\n", i, &s[i], v)
}
}
Demo program 1 output
#####
original slice
len:5, cap:5
0 0xc000074050 ola
1 0xc000074060 nihao
2 0xc000074070 salut
3 0xc000074080 oi
4 0xc000074090 kamusta
#####
slice of slice
len:2, cap:3
0 0xc000074070 salut
1 0xc000074080 oi
#####
side effect: modified new slice index
original slice
len:5, cap:5
0 0xc000074050 ola
1 0xc000074060 nihao
2 0xc000074070 salut
3 0xc000074080 oi
4 0xc000074090 MUDOU ## original value was replaced by the new index from the new slice
slice of slice
len:3, cap:3
0 0xc000074070 salut
1 0xc000074080 oi
2 0xc000074090 MUDOU
What do you notice with the output? MUDOU
doesn’t anymore appear in the original slice. It’s as if the new slice has its own backing array. That’s right! When the length and capacity of a slice is equal, and you append a new item to it, a new backing array is created. Look at the length and capacity of the new slice — they’re both 3. Compared from demo program 1, we copied from 2nd to 4th index (previously, it was 2nd to 3rd). With 2:5
, we’ve essentially maxed the capacity of the original slice, so it can only provide a capacity of 3 from the 2nd index. We reached the maximum capacity, so when we addded MUDOU
, it created a new backing array. Take a look at the memory addresses of the items of both slices, they’re different!
Now, this is the concept behind the three-index slice we’ll see on the next journal.
Demo program 2
func main() {
fmt.Println("#####")
fmt.Println("original slice")
greetings := []string{"ola", "nihao", "salut", "oi", "kamusta"}
displaySlice(greetings)
fmt.Println("\n#####")
fmt.Println("slice of slice")
greetings1 := greetings[2:5] // changed from [2:4] to [2:5]
displaySlice(greetings1)
fmt.Println("\n#####")
fmt.Println("only the new slice has the new item")
greetings1 = append(greetings1, "MUDOU")
fmt.Println("original slice")
displaySlice(greetings)
fmt.Println("slice of slice")
displaySlice(greetings1)
}
func displaySlice(s []string) {
fmt.Printf("len:%v, cap:%v\n", len(s), cap(s))
for i, v := range s {
fmt.Printf("%v %v %v\n", i, &s[i], v)
}
}
Demo program 2 output:
#####
original slice
len:5, cap:5
0 0xc000074050 ola
1 0xc000074060 nihao
2 0xc000074070 salut
3 0xc000074080 oi
4 0xc000074090 kamusta
#####
slice of slice
len:3, cap:3
0 0xc000074070 salut
1 0xc000074080 oi
2 0xc000074090 kamusta
#####
only the new slice has the new item
original slice
len:5, cap:5
0 0xc000074050 ola
1 0xc000074060 nihao
2 0xc000074070 salut
3 0xc000074080 oi
4 0xc000074090 kamusta
slice of slice
len:4, cap:6
0 0xc000072180 salut
1 0xc000072190 oi
2 0xc0000721a0 kamusta
3 0xc0000721b0 MUDOU