Introduction:
There is such a problem when learning the slicing type of go language.
First, in go, the slice type variable actually stores an address, which is the address of the first element of the underlying array it references, or the address of the array.
(I)
Code 1:
package main import "fmt" func change(a []int) { //Here is the address a[0] = 2 fmt.Printf("%p\n", a) //0xc0000d6030 fmt.Println(a) //[2 0 0 0 0] } func main() { s := make([]int, 5) fmt.Printf("s Address of:%p |s Length of:%d |s Capacity of:%d\n", s, len(s), cap(s)) //S address: 0xc0000d6030 |s length: 5 |s capacity: 5 fmt.Println(s) //[0 0 0 0 0] change(s) fmt.Println(s) //0xc0000d6030 fmt.Printf("%p\n", s) //0xc0000d6030 }
Output 1:
s Address of:0xc0000d6030 |s Length of:5 |s Capacity of:5 [0 0 0 0 0] 0xc0000d6030 [2 0 0 0 0] [2 0 0 0 0] 0xc0000d6030
Summary:
1. In the slice incoming function, the formal parameter is a copy of the actual parameter. Although the actual parameter and the formal parameter do not occupy the same memory space, they both point to the same underlying array.
2. When the formal parameter performs relevant operations (adding elements and changing the value of elements), the actual parameters will also change, because they all point to the same underlying array
(II)
Both formal parameters and arguments point to the same array. Changing the values in the array through formal parameters above will also affect the arguments. Let's try adding an element
Code 2:
package main import "fmt" func change(a []int) { a = append(a, 1) //When the slice is expanded, you find another place to put the data address, and then change the place. The original place is not enough fmt.Printf("%p\n", a) //0xc000016280 fmt.Println(a) //[0 0 0 0 0 1] } func main() { s := make([]int, 5) fmt.Printf("s Address of:%p |s Length of:%d |s Capacity of:%d\n", s, len(s), cap(s))//Address of s: 0xc00000123c0 length of s: 5 capacity of s: 5 fmt.Println(s)//[0 0 0 0 0] change(s) fmt.Println(s) //[0 0 0 0 0] fmt.Printf("%p\n", s) //0xc0000123c0 }
Output 2:
s Address of:0xc0000123c0 |s Length of:5 |s Capacity of:5 [0 0 0 0 0] 0xc000016280 [0 0 0 0 0 1] [0 0 0 0 0] 0xc0000123c0
be careful:
According to the printing results, it is found that the printing results of arguments and formal parameters are different. Why?
reason:
1.s as an argument, its capacity is 5, that is, the memory area pointed to by s can only hold 5 elements,
2. When an argument is passed to a formal parameter, both the argument and the formal parameter point to the same memory and area, that is, an area with a capacity of 5
3. When adding elements to formal parameters, if they find that this area is not enough, they will find another place to put the original data and newly added data in this new place
4. Therefore, the address pointed to by the formal parameter is changed
5. According to this principle, if the array capacity is sufficient, the address will not change after adding elements, so the change of formal parameters will not affect the actual parameters. See the following example
(III)
Code 3:
package main import "fmt" func change(a []int) { a = append(a, 1) fmt.Printf("%p\n", a)//0xc00000c2c0 fmt.Println(a)//[0 0 0 0 0 1] } func main() { s := make([]int, 5, 8) fmt.Printf("s Address of:%p |s Length of:%d |s Capacity of:%d\n", s, len(s), cap(s)) //Address of s: 0xc000000c2c0 length of s: 5 capacity of s: 8 fmt.Println(s) //[0 0 0 0 0] change(s) fmt.Println(s)//[0 0 0 0 0] fmt.Printf("%p\n", s)//0xc00000c2c0 }
Output 3:
s Address of:0xc00000c2c0 |s Length of:5 |s Capacity of:8 [0 0 0 0 0] 0xc00000c2c0 [0 0 0 0 0 1] [0 0 0 0 0] 0xc00000c2c0
be careful:
A problem is found. The prediction is different from the result. The addresses of formal parameters and arguments are the same, but the result is different.
reason:
1. The slice s length is 5, that is, it can only see 5 elements of the underlying array
2. When the array length becomes 6, the slice s cannot see the following elements
3. How can I see the following elements and slice them again
1. Argument s and parameter a point to the same memory
2. Only the predefined length is 5 during s initialization
3. The expansion of parameter slice variable a is that after the length is changed to 6, the actual parameter s cannot see the elements behind the slice. It is necessary to slice again (in fact, move the right pointer of s backward and increase the length of s), so that the change can be seen
Code 4:
package main import "fmt" func change(a []int) { a=append(a,1,2) fmt.Printf("a Address of:%p |a Length of:%d |a Capacity of:%d\n",a, len(a), cap(a))//Address of a: 0xc000000c2c0 | length of a: 7 | capacity of a: 8 fmt.Printf("a Value of:%v\n",a)//Value of a: [0 1 2] } func main() { s:=make([]int,5,8) fmt.Printf("s Address of:%p |s Length of:%d |s Capacity of:%d\n", s, len(s), cap(s)) //Address of s: 0xc000000c2c0 length of s: 5 capacity of s: 8 fmt.Printf("section s Value of:%v\n",s)//Value of slice s: [0] change(s) s=s[:] //Slice, you can see the value added later in the slice fmt.Printf("s Address of:%p |s Length of:%d |s Capacity of:%d\n", s, len(s), cap(s))//Address of s: 0xc000000c2c0 length of s: 5 capacity of s: 8 fmt.Printf("section s Value of:%v\n",s)//Value of slice s: [0] }
Output 4:
s Address of:0xc00000c2c0 |s Length of:5 |s Capacity of:8 section s Value of:[0 0 0 0 0] a Address of:0xc00000c2c0 |a Length of:7 |a Capacity of:8 a Value of:[0 0 0 0 0 1 2] s Address of:0xc00000c2c0 |s Length of:5 |s Capacity of:8 section s Value of:[0 0 0 0 0]