This is the fourth day of my participation in the August More text Challenge. For details, see:August is more challenging

The first question

Can you guess what is printed in x and y? And why is that? What are the points of knowledge?

package main

import (
	"fmt"
)

func main() {
	x := []int{1, 2, 3}
	y := x[:2]
	y = append(y, 10)
	fmt.Println("x=", x, &x[0])
	fmt.Println("y=", y, &y[0])

	y = append(y, 20)
	fmt.Println("y=", y, &y[0])
	y[0] = 20
	for i := 0; i < 10; i++ {
		y = append(y, i)
	}
	fmt.Println("y=", y, &y[0])
}
Copy the code

The answer

Package main import (" FMT ") func main() {x := []int{1, 2, 3} y := x[:2]// [1] y = append(y, 10) / / 【 2 】 FMT. Println (" = "x, x, and x [0]) / / x = [10] 1 2 0 xc0000b6020 FMT. Println (" =" y, y, &y[0]) //y= [1 2 10] 0xc0000b6020 y= append(y, 20)// [3] FMT.Println("y=", y, &y[0]) //y= [1 2 10 20] 0xc0000ac030 y[0] = 20// [4] for I := 0; i < 10; Println("y=", y, &y[0]) //y= [20 2 10 20 0 1 2 3 4 5 6 7 8 9] 0xc0000Ba000 [5]}Copy the code

explain

  • [1] Because y is x’s slice {1,2}, y and x point to the same memory address;
  • [2] because y refers to the same memory address as x, when append a value, it will squeeze out 3, so x and y are both 1,2,10
  • [3] Then y appned again, exceeding its original size of 3, and a larger array will be allocated to hold it. A separate memory address will be created for y (y is independent and has nothing to do with x). So y is 1,2,10, 20, and x is still 1,2,10
  • [4] since y already points to a new memory address, change the value of subscript 0 to 10, so y is 20,2,10,20
  • [5] When slice is expanded, a larger memory is created, and the previous data is copied to it, then the y point address changes

knowledge

Slice implementation Principle

type Slice struct {
	ptr   unsafe.Pointer 		// Array pointer
	len   int                   // slice length
	cap   int                 // slice capacity
}
Copy the code

Slice’s data structure, a pointer to the actual array address PTR, slice’s length len and capacity cap, can be automatically reallocated to generate a new slice if the underlying array is insufficient. In practice, it is best to anticipate a cap in the first place. This avoids repeated reallocation of memory when using Append and reduces unnecessary performance costs.

For example,

package main

import (
	"fmt"
)

func main() {
	var data = make([]int, 1, 1)
	fmt.Println("data=", data, &data[0])
	data = append(data, 1)
	fmt.Println("data=", data, &data[0])
	for i := 0; i < 10; i++ {
		data = append(data, i)
		fmt.Println("i=%d,data=%v\n", i, &data[0])

	}
}
Copy the code

The results of

Data = [0 1] 0xc0000B4030 // [2] Data = [0 1] 0xc0000B6040 // [3] Slice. Len++, Slice I =%d,data=%v 2 0xc0000ba000 I =%d,data=%v 3 0xc0000Ba000 Return Slice I =%d,data=%v 4 0xc0000ba000 // = I =%d,data=%v 5 0xc0000Ba000 // = I =%d,data=%v 6 0xc0000bc000 I =%d,data=%v 7 0xC0000bc000 // Ibid. I =%d,data=%v 8 0xC0000bc000 // IbidCopy the code

When selecting capacity expansion, follow the following rules:

If the original Slice size is smaller than 1024, the new Slice size is increased by twice. If the original Slice size is greater than or equal to 1024, the new Slice size is increased by 1.25 times

conclusion

When creating slices, you can pre-allocate the capacity based on actual requirements to avoid the expansion operation (Append) during the addition process, which improves performance

reference

Golang language slice implementation principle and use method

Golang Slice principle