This is a creation in Article, where the information may have evolved or changed.
Look at this code first, and the result is [0 2 3]
that a lot of people can answer it correctly.
func modify(s []int) { s[0] = 0}func main() { s := []int{1, 2, 3} modify(s) fmt.Println(s)}
Then change it a little bit and guess the result.
func pop(s []int) { s = s[:len(s)-1]}func main() { s := []int{1, 2, 3} pop(s) fmt.Println(s)}
If you think the output [1 2]
then you are wrong, and the result is [1 2 3]
, you may find it strange that slice is a reference to semantics which in the first example has proved, why the second example is not so.
We'll add some output to the intermediate process, and then we'll look at
func pop(s []int) { fmt.Printf("[pop] s addr:%p\n", &s) s = s[:len(s)-1] fmt.Println("[pop] s value:", s)}func main() { s := []int{1, 2, 3} fmt.Printf("[main] s addr:%p\n", &s) pop(s) fmt.Println("[main] s value:", s)}
Run the above code output as follows
[main] s addr:0xc082004640[pop] s addr:0xc0820046c0[pop] s value: [1 2][main] s value: [1 2 3]
To see the above results, it is possible to know that pop()
the s
reference is not a copy, although the pop()
internal modification succeeds, but does not affect the main()
in s
. But the first example has been modified, and that's why.
The following is a look at the implementation of slice, you can clearly understand the reason.
The slice is implemented by fixed-length arrays. When adding elements to slice using the built-in function append()
, the space is redistributed if the underlying array length is exceeded (similar to the vector for C + +).
Slice can be thought of as the following structure (regardless of the slice capacity). Lenght
represents the length of the slice, ' zerothelement represents the head pointer of the underlying array
type sliceHeader struct { Length int ZerothElement *byte}
Referring to the definition of this struct and the following description, it is clear to understand the two examples of the beginning.
What if we need to pass slice as a function parameter and the function modifies slice? Here are three ways to say it.
1. Use the slice pointer as a parameter instead of slice
func modify(s *[]int) { // do something}
2. Make the modified slice in the function as the return value, assign the function return value to the original slice
func modify(s []int) []int { // do something return s}func main() { s := []int{1, 2, 3} s = modify(s)}
3. How to make a function as a slice pointer
type slice []intfunc (s *slice) modify() { // do something}