The program below has unexpected output.
func main(){
s:=[]int{5}
s=append(s,7)
s=append(s,9)
x:=append(s,11)
y:=append(s,12)
fmt.Println(s,x,y)
}
output: [5 7 9] [5 7 9 12] [5 7 9 12]
Why is the last element of x
12
?
A slice is only a window over part of an array, it has no specific storage.
This means that if you have two slices over the same part of an array, both slices must "contain" the same values.
Here's exactly what happens here :
append
, you get a new slice of size 2
over an underlying array of size 2
.append
, you get a new slice of size 3
but the underlying array is of size 4
(append
usually allocates more space than the immediately needed one so that it doesn't need to allocate at every append).append
doesn't need a new array. So x
and y
both will use the same underlying array as the precedent slice s
. You write 11
and then 12
in the same slot of this array, even if you get two different slices (remember, they're just windows).You can check that by printing the capacity of the slice after each append :
fmt.Println(cap(s))
If you want to have different values in x
and y
, you should do a copy, for example like this :
s := []int{5}
s = append(s, 7)
s = append(s, 9)
x := make([]int,len(s))
copy(x,s)
x = append(x, 11)
y := append(s, 12)
fmt.Println(s, x, y)
Another solution here might have been to force the capacity of the array behind the s
slice to be not greater than the needed one (thus ensuring the two following append
have to use a new array) :
s := []int{5}
s = append(s, 7)
s = append(s, 9)
s = s[0:len(s):len(s)]
x := append(s, 11)
y := append(s, 12)
fmt.Println(s, x, y)
See also Re-slicing slices in Golang
dystroy explained it very well. I like to add a visual explanation to the behaviour.
A slice is only a descriptor of an array segment. It consists of a pointer to the array (ptr), the length of the segment (len), and capacity (cap).
+-----+
| ptr |
|*Elem|
+-----+
| len |
|int |
+-----+
| cap |
|int |
+-----+
So, the explanation of the code is as follow;
func main() {
+
|
s := []int{5} | s -> +-----+
| []int | ptr +-----> +---+
| |*int | [1]int| 5 |
| +-----+ +---+
| |len=1|
| |int |
| +-----+
| |cap=1|
| |int |
| +-----+
|
s = append(s,7) | s -> +-----+
| []int | ptr +-----> +---+---+
| |*int | [2]int| 5 | 7 |
| +-----+ +---+---+
| |len=2|
| |int |
| +-----+
| |cap=2|
| |int |
| +-----+
|
s = append(s,9) | s -> +-----+
| []int | ptr +-----> +---+---+---+---+
| |*int | [4]int| 5 | 7 | 9 | |
| +-----+ +---+---+---+---+
| |len=3|
| |int |
| +-----+
| |cap=4|
| |int |
| +-----+
|
x := append(s,11) | +-------------+-----> +---+---+---+---+
| | | [4]int| 5 | 7 | 9 |11 |
| | | +---+---+---+---+
| s -> +--+--+ x -> +--+--+
| []int | ptr | []int | ptr |
| |*int | |*int |
| +-----+ +-----+
| |len=3| |len=4|
| |int | |int |
| +-----+ +-----+
| |cap=4| |cap=4|
| |int | |int |
| +-----+ +-----+
|
y := append(s,12) | +-----> +---+---+---+---+
| | [4]int| 5 | 7 | 9 |12 |
| | +---+---+---+---+
| |
| +-------------+-------------+
| | | |
| s -> +--+--+ x -> +--+--+ y -> +--+--+
| []int | ptr | []int | ptr | []int | ptr |
| |*int | |*int | |*int |
| +-----+ +-----+ +-----+
| |len=3| |len=4| |len=4|
| |int | |int | |int |
| +-----+ +-----+ +-----+
| |cap=4| |cap=4| |cap=4|
| |int | |int | |int |
+ +-----+ +-----+ +-----+
fmt.Println(s,x,y)
}