使用值接收器附加到具有足够容量的切片

can someone help me understand what happens here?

package main

import (
    "fmt"
)

func appendString(slice []string, newString string) {
    slice = append(slice, newString)
}

func main() {
    slice := make([]string, 0, 1)
    appendString(slice, "a")
    fmt.Println(slice)
}

I know about the slice header and the need to use a pointer receiver. But here, as the underlying array has enough capacity I would expect append to work anyways (just adding the new value to the underlying array and the original [copied] header working as expected)

What is wrong with my assumptions?

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]