Please explain me such strange behavior of this code snippet (output depends only on n value in main()) [code is here]
I work with go version: go1.14.4 windows/amd64
package main
import "fmt"
func fn(s []st) {
var y st
y = st{"fn()", 777}
s = append(s, y)
fmt.Println("1. fn appends:", s)
s[0].a = "???"
s[len(s)-1].a = "!!!"
fmt.Println("2. fn changes:", s)
s = s[:0]
fmt.Println("3. fn deletes all:", s)
}
type st struct {
a string
b int
}
func main() {
n := 2 // change n by 1, 2, 3, 4, ...
var x []st
for i := 0; i < n; i++ {
x = append(x, st{"main", i})
}
fmt.Println("main before fn(): ", x)
fn(x)
fmt.Println("main after fn(): ", x)
}
Output:
main before fn(): [{main 0} {main 1}]
1. fn appends: [{main 0} {main 1} {fn() 777}]
2. fn changes: [{??? 0} {main 1} {!!! 777}]
3. fn deletes all: []
main after fn(): [{main 0} {main 1}]
n = 2
With n :=2 in last line of Output x[0].a == "main" (pls look above)
With n :=3 in last line of Output x[0].a == "???" (pls look below)
Output:
main before fn(): [{main 0} {main 1} {main 2}]
1. fn appends: [{main 0} {main 1} {main 2} {fn() 777}]
2. fn changes: [{??? 0} {main 1} {main 2} {!!! 777}]
3. fn deletes all: []
main after fn(): [{??? 0} {main 1} {main 2}]
n = 3
I believe there are a few things that are causing some confusion.
When you append to the slice here
var y st
y = st{"fn()", 777}
s = append(s, y)
fmt.Println("1. fn appends:", s)
I think you are allocating a new backing array because the cap has been exceeded. So this is why you do not see the “???” and the “!!!” reflected in the final println statement.
If you were to comment those lines out like I’ve done here https://play.golang.org/p/bSUjxO1tXhD
Then a new backing array is not created so you see the changes reflected in the final println statement in main.
Check out this playground to see how a new backing array is created and the cap of s becomes 4 while the cap of x in main remains 2 https://play.golang.org/p/oCBg1lzrCEV
Hopefully this is helpful.
I know I didn’t attempt to answer why the s =[:0] does not effect the slice in main, but I believe this has to do with not actually effecting the underlying array but only changing what part of it s points to, while x still points to the full underlying array.