Let's add a final print statement to see the result:
slice := make([]string, 0, 1)
fmt.Println(cap(slice))
appendString(slice, "a")
fmt.Println(slice)
And the output will be (try it on the Go Playground):
1
[]
Which is correct. One could expect the output to be:
1
[a]
The reason why this is not the case is because even though a new backing array will not be allocated, the slice header in the slice
variable inside main()
is not changed, it will still hold length = 0
. Only the slice header stored in the slice
local variable inside appendString()
(the parameter) is changed, but this variable is independent from main's slice
.
If you were to reslice main's slice
, you will see that the backing array does contain the new string:
slice := make([]string, 0, 1)
fmt.Println(cap(slice))
appendString(slice, "a")
fmt.Println(slice)
slice = slice[:1]
fmt.Println(slice)
Now output will be (try it on the Go Playground):
1
[]
[a]
This is why the builtin append()
has to return the new slice: because even if no new backing array is needed, the slice header (which contains the length) will have to be changed (increased) if more than 0 elements are appended.
This is why appendString()
should also return the new slice:
func appendString(slice []string, newString string) []string {
slice = append(slice, newString)
return slice
}
Or short:
func appendString(slice []string, newString string) []string {
return append(slice, newString)
}
Which you have to reassign where you use it:
slice := make([]string, 0, 1)
fmt.Println(cap(slice))
slice = appendString(slice, "a")
fmt.Println(slice)
And then you get the expected outcome right away (try it on the Go Playground):
1
[a]