“This is the 20th day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

Slice slice’s underlying data is an array. Slice is a wrapper around an array that describes a fragment of an array. Both can access individual elements with subscripts. Arrays are of fixed length and cannot be changed once the length is defined. Slicing is very flexible and can be dynamically expanded. The type of slice has nothing to do with the length. An array is a contiguous piece of memory. Slice is actually a structure containing three fields: length, capacity, and the underlying array. The data structure of the slice is shown as follows:

// runtime/slice.go
type slice struct {
    array unsafe.Pointer // A pointer to an array
    len   int // The current slice length
    cap   int // The current slice capacity}Copy the code

1 overview

  • Slicing is built around the concept of dynamic arrays. But slicing itself is not a dynamic array, but an abstraction of the underlying array.
  • Automatically resize as needed
  • In contrast to arrays, the length of slices can be modified at run time
  • A slice does not hold a specific value. A slice is a reference type
  • Equivalent to an ArrayList in Java

2 the introduction

Because the length of an array is fixed and is part of a type, arrays have many limitations. Such as:

func arraySum(x [3]int) int{
    sum := 0
    for _, v := range x{
        sum = sum + v
    }
    return sum
}
Copy the code

This summation function accepts only [3] ints, and nothing else. For example,

a := [3]int{1, 2, 3}

We already have three elements in array A, so we can’t add any more elements to array A.

3. Definition of slice

Var name []T ::: :

Name: indicates the name of the variable. T: indicates the element type in the slice, for example:

func main(a) {
	// Declare the slice type
	var a []string              // Declare a string slice
	var b = []int{}             // Declare an integer slice and initialize it
	var c = []bool{false.true} // Declare a Boolean slice and initialize it
	var d = []bool{false.true} // Declare a Boolean slice and initialize it
	fmt.Println(a)              / / []
	fmt.Println(b)              / / []
	fmt.Println(c)              //[false true]
	fmt.Println(a == nil)       //true
	fmt.Println(b == nil)       //false
	fmt.Println(c == nil)       //false
	// FMT.Println(c == d) // Slice is a reference type and can only be compared to nil
}
Copy the code

::: Tip Slice length and capacity Slice has its own length and capacity, we can use the built-in len() function to find the length, using the built-in cap() function to find the capacity of the slice. : : :

Define slices based on arrays

Since the bottom layer of a slice is an array, we can define a slice based on an array.

func main(a) {
	// Define slices based on arrays
	a := [5]int{55.56.57.58.59}
	b := a[1:4]                     // Create a slice based on array A, including elements A [1],a[2],a[3]
	fmt.Println(b)                  / / 57, 58 [56]
	fmt.Printf("type of b:%T\n", b) //type of b:[]int
}
Copy the code

The following modes are also supported:

c := a[1:] / / 58 59 [56, 57]
d := a[:4] / / [55, 56, 57, 58]
e := a[:]  //[55 56 57 58 59]
Copy the code

5 Slice and slice

In addition to getting slices based on arrays, we can also get slices by slicing.

func main(a) {
	// Slice and slice
	a := [...]string{"Beijing"."Shanghai"."Guangzhou"."Shenzhen"."Chengdu"."Chongqing"}
	fmt.Printf("a:%v type:%T len:%d cap:%d\n", a, a, len(a), cap(a))
	b := a[1:3]
	fmt.Printf("b:%v type:%T len:%d cap:%d\n", b, b, len(b), cap(b))
	c := b[1:5]
	fmt.Printf("c:%v type:%T len:%d cap:%d\n", c, c, len(c), cap(c))
}
Copy the code

The output

A :[Beijing Shanghai Guangzhou Shenzhen Chengdu Chongqing]type: [6]string len:6  cap:6B :[Shanghai guangzhou]type: []string len:2  cap:5C :[Guangzhou shenzhen Chengdu Chongqing]type: []string len:4  cap:4
Copy the code

::: warning When the slice is sliced again, the index cannot exceed the length of the original array. Otherwise, an error may occur. : : :

6 Use make() to construct slices

Make ([]T, size, cap) :: tip make([]T, size, cap) ::

  • T: the element type of the slice
  • Size: the number of elements in the slice
  • Cap: indicates the slice capacity

For example, the following

func main(a) {
	a := make([]int.2.10)
	fmt.Println(a)      / / [0, 0]
	fmt.Println(len(a)) / / 2
	fmt.Println(cap(a)) / / 10
}
Copy the code

In the code above, 10 internal storage Spaces of A have been allocated, but only 2 are actually used. Capacity does not affect the number of current elements, so len(a) returns 2 and cap(a) returns the capacity of the slice.

The difference between making initialization and declaring normal slices

    // Initialize the slice with make and assign the initial value
	s1:=make([]int.5.10)
	fmt.Println(s1) //[0 0 0 0 0]
	// Declare slices but do not initialize assignments
	var s2 []int
	fmt.Println(s2==nil,s1==nil)//true false
	fmt.Println(len(s1),len(s2)) / / 5 0
Copy the code

The nature of slicing

::: Tip Slice Essence The essence of a slice is to encapsulate the underlying array. It contains three pieces of information: the pointer to the underlying array, the length of the slice (Len), and the capacity of the slice (CAP). For example, we now have an array a := [8]int{0, 1, 2, 3, 4, 5, 6, 7}, sliced s1 := a[:5], as shown in the following diagram. : : :

Section S2 := a[3:6], corresponding schematic diagram is as follows:

Slices cannot be directly compared

Slices cannot be compared, and we cannot use the == operator to determine whether two slices contain all equal elements. The only valid comparison operation for slicing is to compare to nil. A nil slice has no underlying array. A nil slice has a length and a capacity of 0. But we can’t say that a slice with both length and capacity 0 is nil, as in the following example:

var s1 []int         //len(s1)=0; cap(s1)=0; s1==nil
s2 := []int{}        //len(s2)=0; cap(s2)=0; s2! =nil
s3 := make([]int.0) //len(s3)=0; cap(s3)=0; s3! =nil
Copy the code

::: warning If a slice is empty, len(s) == 0 should not be used to determine if s == nil. : : :

8 Assigned copy of slice

The following code demonstrates that both variables share the underlying array before and after the copy. It is important to note that changes to one slice affect the contents of the other.

8.1 General Assignment

func main(a) {
	s1 := make([]int.3) / / [0 0 0]
	s2 := s1             // Assign s1 directly to s2. S1 and S2 share the same underlying array
	s2[0] = 100
	fmt.Println(s1) / / [100 0 0]
	fmt.Println(s2) / / [100 0 0]
}
Copy the code

8.2 Copy () is used to copy slices

func main(a) {
	a := []int{1.2.3.4.5}
	b := a
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(b) //[1 2 3 4 5]
	b[0] = 1000
	fmt.Println(a) //[1000 2 3 4 5]
	fmt.Println(b) //[1000 2 3 4 5]
}
Copy the code

Since slices are references, both A and B actually refer to the same memory address. When you change B, you change the value of A.

Go’s built-in copy() function can quickly copy data from one slice to another. The format of copy() function is as follows:

::: tip Format copy(destSlice, srcSlice []T)

  • SrcSlice: indicates the slice of data source
  • DestSlice: indicates the destination slice

: : :

func main(a) {
	// copy() copies slices
	a := []int{1.2.3.4.5}
	c := make([]int.5.5)
	copy(c, a)     // Use copy() to copy the elements in slice A to slice C
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
}
Copy the code

9 Slice traversal

Slice traversal is the same as array traversal, supporting index traversal and for range traversal similar to Java’s enhanced foreach.

func main(a) {
	s := []int{1.3.5}

	for i := 0; i < len(s); i++ {
		fmt.Println(i, s[i])
	}

	for index, value := range s {
		fmt.Println(index, value)
	}
}
Copy the code

10 The append() method adds elements to the slice

The Go language’s built-in function Append () can dynamically add elements to slices. Each slice points to an underlying array that can hold a certain number of elements. When the underlying array cannot contain new elements, the slice will be automatically expanded according to certain policies, and the underlying array pointed to by the slice will be replaced. The “expand” operation usually occurs when the append() function is called. For example

func main(a) {
	//append() adds elements and slices, automatically initializes slices
	var numSlice []int
	for i := 0; i < 10; i++ {
		numSlice = append(numSlice, i)
		fmt.Printf("%v len:%d cap:%d ptr:%p\n", numSlice, len(numSlice), cap(numSlice), numSlice)
	}
}
Copy the code

The output

[0]  len:1  cap:1  ptr:0xc0000a8000
[0 1]  len:2  cap:2  ptr:0xc0000a8040
[0 1 2]  len:3  cap:4  ptr:0xc0000b2020
[0 1 2 3]  len:4  cap:4  ptr:0xc0000b2020
[0 1 2 3 4]  len:5  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5]  len:6  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6]  len:7  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6 7]  len:8  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6 7 8]  len:9  cap:16  ptr:0xc0000b8000
[0 1 2 3 4 5 6 7 8 9]  len:10  cap:16  ptr:0xc0000b8000
Copy the code

Append multiple elements at once

var citySlice []string
// Appends an element
citySlice = append(citySlice, "Beijing")
// Append multiple elements
citySlice = append(citySlice, "Shanghai"."Guangzhou"."Shenzhen")
// Append slices
a := []string{"Chengdu"."Chongqing"}
citySlice = append(citySlice, a...)
fmt.Println(citySlice) //[Beijing Shanghai Guangzhou Shenzhen Chengdu Chongqing]
Copy the code

11 Delete elements from the slice

There is no special way to delete slice elements in Go, we can use the features of slice itself to delete elements. The code is as follows:

func main(a) {
	// Remove the element from the slice
	a := []int{30.31.32.33.34.35.36.37}
	// Delete the element with index 2
	a = append(a[:2], a[3:]...). fmt.Println(a)//[30 31 33 34 35 36 37]
}
Copy the code

12 Slice and delete elements for another example

    arr := [...]int{1.3.5.7.9.11}
	// Assign array arr to slice s1
	s1:=arr[:]
	fmt.Println(s1)
	// Prints the memory address of S1
	fmt.Printf("S1 memory address before deleting element %p\n", s1)
	[1, 7, 9, 11]
	s1=append(s1[:1],s1[3:]...).// Prints the memory address of S1
	fmt.Printf("S1 memory address %p\n after element deletion", s1)
	//s1 deletes elements with values [1, 7, 9, 11]
	fmt.Println(s1)
	//s1 points to array arr as [1, 7, 9, 11, 9, 11]
	fmt.Println(arr) //[1 7 9 11 9 11]
Copy the code

: : : tip

  • Slicing never stores values (slicing refers to an underlying array, which occupies a contiguous chunk of memory).
  • A = append(a[:index], a[index+1:]…)

: : :

::: Danger slice built-in function summary

  • Len gets the length of the slice
  • Cap gets the maximum size of slice
  • Append appends one or more elements to slice and returns a slice of the same type as Slice
  • Copy copies elements from the SRC of the source slice to the destination DST and returns the number of copied elements

: : :