“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
: : :