Hi,
I discovered a strange behavior when appending to slices:
Why does
package main
import (
"fmt"
)
var (
a []int
aa [][]int
)
func main() {
a = make([]int, 4, 4)
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
for i := 0; i < 4; i++ {
a[0] = a[0] * 2
a[1] = a[1] * 3
a[2] = a[2] * 4
a[3] = a[3] * 5
aa = append(aa, []int{a[0], a[1], a[2], a[3]}) //[[2 6 12 20] [4 18 48 100] [8 54 192 500] [16 162 768 2500]]
//aa = append(aa, a) //[[16 162 768 2500] [16 162 768 2500] [16 162 768 2500] [16 162 768 2500]]
//aa = append(aa, a[:]) //[[16 162 768 2500] [16 162 768 2500] [16 162 768 2500] [16 162 768 2500]]
}
fmt.Println(aa)
}
result in
[[2 6 12 20] [4 18 48 100] [8 54 192 500] [16 162 768 2500]]
however, appending the complete slice instead
…
aa = append(aa, a)
…
results in
[[16 162 768 2500] [16 162 768 2500] [16 162 768 2500] [16 162 768 2500]]
?
Or even copying the slice by
…
aa = append(aa, a[:])
…
leads to this annoying behavior,
If that is not a bug, it’s at least a very bad feature!
amnon
(amnon bc)
October 20, 2022, 9:19am
2
yes you end up with each element of aa
pointing to the same single instance of a
so if you double a[0]
, then you have doubled aa[0][0]
, aa[1][0]
, aa[2][0]
and aa[3][0]
as they all point to the same memory location. That is how slices work.
Have a look at Go Slices: usage and internals - The Go Programming Language
1 Like
Thank you for the good explanation!
In that case this is a less quick and more dirty solution:
…
var b []int
b = make([]int, 4, 4)
for i := 0; i < len(a); i++ {
b[i] = a[i]
}
aa = append(aa, b)
…
But it’s not intuitive and definitely a source of really hard-to-find bugs.
amnon
(amnon bc)
October 20, 2022, 3:16pm
4
I had tried
copy(b,a)
as well, however I made the mistake to allocate the memory only once and reassigned values inside loop. And this did not work:
for … {
…
a[0] = a[0] * 2
…
b := make([]int, 4, 4)
copy(b, a)
aa = append(aa, b)
…
}
Your approach succeeds, but variable b must be reallocated each time.
b := make([]int, 4, 4)
for … {
…
a[0] = a[0] * 2
…
copy(b, a)
aa = append(aa, b)
…
}
mje
(Jeff Emanuel)
October 21, 2022, 7:51pm
6
If you don’t create a new slice with make, then you are back to sharing the slice over and over.