Slice processing looks like an error in Go

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
1 Like

Hey Vladimir!

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.

Hi Conner

Exhaustive answer.
Thanks a lot! :slight_smile:

1 Like

No problem!

Hopefully it was somewhat helpful.
I’m still relatively new to go so my explanations can be opaque :joy: