We introduced arrays earlier, and I’m sure you’re aware of the inconvenience of Go arrays. Once an array is defined in Go, you can’t change its size. That’s where slicing comes in.

Next, let’s introduce a difficult point in Go: slice, and realize the charm of Go, a low-level code language.

1. Declare slices

var name []T
Copy the code
  • Name: slice

  • T: Element type in slice

You can think of a slice simply as an array with no defined size.

Slice type variables do not hold values, only (length len, capacity cap, pointer to the underlying array point), so slice objects are not allocated memory before initialization, so there is no default value = nil at all

package  main
import "fmt"
/ / section
 
func main(a){
  // The slice is not initialized
	var slice []int
	fmt.Println(slice == nil)}Copy the code

Output results:

true 
Copy the code

2. Initialize the slice

(1) Directly initialize slices

var s1 = []int{1.2} // Define a slice to hold int elements
Copy the code

(2) Get slice data from array

// Slice from the array
 a1 := [...]int{1.2.3.4.5.6}
 a2 := a1[0:4] // get [1,2,3,4], just like the python slice
Copy the code

3. Create slices using the make function

//make( []T, size, cap )
// Create a shape slice of length 6 and capacity 10
a1 := make([]int.6.10) 
Copy the code
  • T: Element type in slice
  • Size: The number of elements (that is, the length) that the slice accesses, obtained by len(a1)
  • Cap: The number of elements (capacity) that a slice is allowed to grow to, obtained by cap(A1)
  • A2 := make([]int,5), size = 5,cap = 5.

4. The difference between length and capacity in slices:

  1. The slice points to an underlying array that stores the slice’s value

  2. The length of a slice is the number of elements it has

  3. The size of a slice is the number of slices from the first element of the slice to the last element of the underlying array

package  main
import "fmt"
/ / section
 
func main(a){
	// The difference between the length and the volume of the slice
	slice := [...]int{1.2.3.4.5.6}
  fmt.Printf("slice:%v len(slice):%d cap(slice):%d\n",slice,len(slice),cap(slice))
  
	newslice := slice[0:2]/ / [1, 2]
	fmt.Printf("newslice:%v len(newslice):%d cap(newslice):%d\n",newslice,len(newslice),cap(newslice))
	
	newslice2 := slice[2:5] / / / three, four, five
	fmt.Printf("newslice2:%v len(newslice2):%d cap(newslice2):%d",newslice2,len(newslice2),cap(newslice2))
}
Copy the code

Output results:

slice:[1 2 3 4 5 6] len(slice):6 cap(slice):6
newslice:[1 2] len(newslice):2 cap(newslice):6
newslice2:[3 4 5] len(newslice2):3 cap(newslice2):4
Copy the code

5. The nature of slicing:

  1. A slice is a box that encloses a contiguous piece of memory.

  2. Slices are reference types, and the real data is stored in the underlying array (slices don’t hold values, values are stored in the underlying array).

package  main
import "fmt"
/ / section
 
func main(a){
	// The difference between the length and the volume of the slice
	slice := [...]int{1.2.3.4.5.6}
	fmt.Printf("slice:%v len(slice):%d cap(slice):%d\n",slice,len(slice),cap(slice))
	newslice := slice[0:4]/ / [1, 2, 3, 4]
	fmt.Printf("newslice:%v len(newslice):%d cap(newslice):%d\n",newslice,len(newslice),cap(newslice))
	
	newslice2 := slice[2:5] / / / three, four, five
	fmt.Printf("newslice2:%v len(newslice2):%d cap(newslice2):%d",newslice2,len(newslice2),cap(newslice2))
	
	// Change the slice median, newSlice and newSlice2 corresponding position values change accordingly
	slice[3] = 100
	fmt.Println("\n after change:")
	fmt.Printf("slice:%v len(slice):%d cap(slice):%d\n",slice,len(slice),cap(slice))
	fmt.Printf("newslice:%v len(newslice):%d cap(newslice):%d\n",newslice,len(newslice),cap(newslice))
	fmt.Printf("newslice2:%v len(newslice2):%d cap(newslice2):%d",newslice2,len(newslice2),cap(newslice2))

	// Change the newslice value, slice and newSlice2 position values also change, both slices share the same underlying array
	newslice[2] = 99
	fmt.Println("\n after another change:")
	fmt.Printf("slice:%v len(slice):%d cap(slice):%d\n",slice,len(slice),cap(slice))
	fmt.Printf("newslice:%v len(newslice):%d cap(newslice):%d\n",newslice,len(newslice),cap(newslice))
	fmt.Printf("newslice2:%v len(newslice2):%d cap(newslice2):%d",newslice2,len(newslice2),cap(newslice2))
}
Copy the code

Output results:

slice:[1 2 3 4 5 6] len(slice):6 cap(slice):6 newslice:[1 2 3 4] len(newslice):4 cap(newslice):6 newslice2:[3 4 5] Len (newslice2):3 cap(newslice2):4  slice:[1 2 3 100 5 6] len(slice):6 cap(slice):6 newslice:[1 2 3 100] len(newslice):4 cap(newslice):6 newslice2:[3 100 5] len(newslice2):3 cap(newslice2):4  slice:[1 2 99 100 5 6] len(slice):6 cap(slice):6 newslice:[1 2 99 100] len(newslice):4 cap(newslice):6 newslice2:[99 100 5] len(newslice2):3 cap(newslice2):4Copy the code

Append () adds elements to the slice

(1) append() appends an element

  1. Calling append must receive the return value with the original slice variable
  2. Append appends the element, and when the original underlying array is no longer sufficient, Go creates a new underlying array to hold the slice
package  main
import "fmt"
// Slice the advanced operation
 
func main(a){
	// Append () appends elements to the slice
	s1 := []string {"Turkey noodles"."Sin ramen"."Soup Man"}
	fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n",s1,len(s1),cap(s1))
	
	Call append must receive the return value with the original slice variable
	s1 = append(s1,"Little Master") // Append to append the element. Go creates a new layer array to hold the slice when the original layer number cannot be assembled
	fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n",s1,len(s1),cap(s1))
}
Copy the code

Output results:

S1 = len(s1)=3 cap(s1)=3 s1= 4 cap(S1)=6Copy the code

(2) Append () appends a slice

package  main
import "fmt"
// Slice the advanced operation
 
func main(a){
	// Append () appends elements to the slice
	s1 := []string {"Turkey noodles"."Sin ramen"."Soup Man"}
	fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n",s1,len(s1),cap(s1))
	
	Call append must receive the return value with the original slice variable
	s1 = append(s1,"Little Master") // Append dynamically appends the elements. When the original underlying array cannot hold enough elements, the slice will start to expand. Go to the underlying array and replace the underlying array with another one
	fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n",s1,len(s1),cap(s1))

	// Call Append to add a slice
	s2 := []string{Crisp Commander."Saint"}
	s1 = append(s1,s2...)/ /... Means to disassemble the slice
	fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d",s1,len(s1),cap(s1))
}
Copy the code

Output results:

S1 =[Turkey Noodle soup master]len(s1)=3 cap(s1)=3S1 =[Turkey noodle soup master master]len(s1)=4 cap(s1)=6S1 =[Turkey Noodles, Ramen soup, Master Master, Crispy Commander saint]len(s1)=6 cap(s1)=6% 
Copy the code

7. Slice the expansion policy

$GOROOT/SRC/runtime/slice. Go source code:

newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
	newcap = cap
} else {
	if old.len < 1024 {
		newcap = doublecap
	} else {
		// Check 0 < newcap to detect overflow
		// and prevent an infinite loop.
		for 0 < newcap && newcap < cap {
			newcap += newcap / 4
		}
		// Set newcap to the requested cap when
		// the newcap calculation overflowed.
		if newcap <= 0 {
			newcap = cap}}}Copy the code

As you can see from the above code:

  1. First, if the new application capacity (CAP) is more than twice the old capacity (old.cap), the final capacity (newCAP) is the new application capacity (CAP).

  2. Otherwise, if the length of the old slice is less than 1024, then the final capacity (newcap) is twice the old capacity (olde.cap), i.e. (newcap =doublecap),

  3. Otherwise, if the old slice length is greater than or equal to 1024, then the final capacity (newcap) starts from the old capacity (old.cap) and increases by 1/4 of the original. (newcap=old.cap,for {newcap += newcap/4}) (newcap=old.cap,for {newcap += newcap/4}) (newcap >= cap)

  4. If the calculated value of the final capacity (CAP) overflows, the final capacity (CAP) is the new requested capacity (CAP).

It is important to note that slicing is scaled differently depending on the type of element in the slice. For example, int and string are scaled differently.

8. The Copy () function

In 5, we learned that changing a value in slice causes the corresponding position in the underlying array to change.

The copy() function in Go can quickly copy the value of one slice into another slice space. Changing the value of the original slice will not affect the new slice.

Copy is a value copy, and equals is a pointer copy.

Copy format:

Copy elements from srcSlice to destSlice

copy(destSlice,srcSlice []T) 
Copy the code
package main

import "fmt"
//copy
func main(a){
	n1 := []int{1.2.3}
	//n2 := n1
	fmt.Printf("n1:%v,len(n1):%d,cap(n1):%d\n",n1,len(n1),cap(n1))
	//fmt.Println(n2)
	
	n3 := make([]int.6.6)
	fmt.Printf("n3:%v,len(n3):%d,cap(n3):%d\n",n3,len(n3),cap(n3))
	// If the source slice length is 6 and the target slice length is 3, only the first 3 slices will be copied
	copy(n1,n3)
	fmt.Printf("n1:%v,len(n1):%d,cap(n1):%d\n",n1,len(n1),cap(n1))
	fmt.Printf("n3:%v,len(n3):%d,cap(n3):%d\n",n3,len(n3),cap(n3))

	n4 := []int{5.6.7}
	// Copy the three values from the source slice to the first three indexes of the target slice
	n5 := copy(n3,n4) //n5 output index reaches the position of 3
	fmt.Printf("n3:%v,len(n3):%d,cap(n3):%d\n",n3,len(n3),cap(n3))
	//copy does not change the value of the source slice, i.e. n4 does not change
	fmt.Printf("n4:%v,len(n4):%d,cap(n4):%d\n",n4,len(n4),cap(n4))
	fmt.Println(n5)
}
Copy the code

Output results:

n1:[1 2 3],len(n1):3,cap(n1):3
n3:[0 0 0 0 0 0],len(n3):6,cap(n3):6
n1:[0 0 0],len(n1):3,cap(n1):3
n3:[0 0 0 0 0 0],len(n3):6,cap(n3):6
n3:[5 6 7 0 0 0],len(n3):6,cap(n3):6
n4:[5 6 7],len(n4):3,cap(n4):3
3
Copy the code

9. Remove elements from slices

package main

import "fmt"
//delete
func main(a){
	// Delete the element whose index is 4, which is 52
	n := []int{12.23.34.43.52.69.70}
	// Split the slice from the index into two slices and join them with append
	n = append(n[:4],n[5:]...). fmt.Println(n) }Copy the code