Go language slice advanced

Keywords: Go Back-end

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]

Posted by novice4eva on Thu, 04 Nov 2021 14:04:46 -0700