Section
Slice is a variable-length sequence of elements of the same type.It is a layer of encapsulation based on the type of array.Support automatic expansion
Slice is a reference type
The internal structure of the slice contains address, length, and capacity
var name []T
func main() { var a []string // Declare a String Slice var b = []int{} // Declare an integer slice and initialize it var c = []bool{true, false} // Declare a Boolean slice and initialize it // var d = []bool{true, false} //Declare a Boolean slice and initialize fmt.Println(a) // [] fmt.Println(b) // [] fmt.Println(c) // [true, false] fmt.Println(a == nil) // true fmt.Println(b == nil) // false fmt.Println(c == nil) // false // fmt.Println(c == d) //Slice is a reference type, does not support direct comparison, can only be compared with nil }
Slice length and capacity
Slices have their own length and capacity, using the built-in len() function for length, and the built-in cap() function for capacity
Define slices based on arrays
func main() { a := [5]int{55, 66, 77, 88, 99} b := a[1:4] fmt.Println(b) // [66, 77, 88] fmt.Printf("type of b: %T\n", b) // type of b: []int b[0] = 1 // Slice b modifies elements affecting a fmt.Println(a) // [55 1 77 88 99] }
Slice-based re-slicing
func main() { a := [...]string{"Beijing", "Shanghai", "Guangzhou", "Shenzhen", "Chengdu", "Xi'an"} 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)) } //a: [Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Xi'an], type: [6]string, len: 6, cap: 6 //b: [Guangzhou, Shanghai], type: []string, len: 2, cap: 5 //c: [Guangzhou, Shenzhen, Chengdu, Xi'an], type: []string, len: 4, cap: 4 // For b, len gets the number of elements, cap gets the start-to-end capacity of B // For c, len gets four elements in slice a, and cap capacity is the capacity from the beginning of C to the end of a
Note: When slicing (b) and re-slicing (c), the index must not exceed the length of the original array, otherwise an error of index out of bounds will occur
Using make() function to construct slices
Creating slices dynamically using the make() function
make([]T, size, cap) // T: Element type of slice // size: Number of elements in the slice // cap: Slice capacity func main() { a := make([]int, 2, 10) fmt.Printf("a: %v, len: %d, cap: %d", a, len(a), cap(a)) } // a: [0 0], len: 2, cap: 10
The nature of slicing
The essence of a slice is an encapsulation of a low-level array, which contains three information: the pointer to the low-level array, the length of the slice (len), and the capacity of the slice (cap).
func main() { a := [8]int{0, 1, 2, 3, 4, 5, 6, 7} s1 := a[:5] // len=5, cap=8, cap is the capacity of a, because the starting value of slice a is the starting value of a s2 := a[3:6] // len=3, cap=5 for s2, cap starting from 3 to the end of a }
Slices cannot be compared directly
You cannot use the ==operator to determine if two slices contain all the same elements
The only valid comparison of slices is with nil
Slices with nil values have no underlying array, and the length and capacity of a slice with nil values are both 0
Note: A slice with length and capacity of 0 is not necessarily nil
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
To determine if a slice is empty, len(s) == 0 should not be used to determine s == nil
Assignment copy of slice
func main() { s1 := make([]int, 5) // [0, 0, 0, 0, 0] s2 := s1[2:] // Share underlying array s2[0] = 100 fmt.Println(s1) // [0 0 100 0 0] fmt.Println(s2) // [100 0 0] }
Note: Modifications to one slice affect the contents of another slice
Traversal of slices
The slice traversal is consistent with the array and can be traversed by index and for range
func main() { 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) } }
The append method adds elements to the slice
- Each slice points to a low-level array that has enough capacity to add new elements
- When the underlying array cannot accommodate new elements, the slice will automatically expand according to a certain strategy, and the underlying array that the slice points to will be replaced
- Expansion often occurs in append() function calls, so we usually need to use the original variable to receive the return value of the append function
func main() { // append() add elements and slice expansion 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) } } // [0] len:1, cap:1, ptr:0xc000016080 // [0 1] len:2, cap:2, ptr:0xc0000160c0 // [0 1 2] len:3, cap:4, ptr:0xc000018180 // [0 1 2 3] len:4, cap:4, ptr:0xc000018180 // [0 1 2 3 4] len:5, cap:8, ptr:0xc000012080 // [0 1 2 3 4 5] len:6, cap:8, ptr:0xc000012080 // [0 1 2 3 4 5 6] len:7, cap:8, ptr:0xc000012080 // [0 1 2 3 4 5 6 7] len:8, cap:8, ptr:0xc000012080 // [0 1 2 3 4 5 6 7 8] len:9, cap:16, ptr:0xc000078000 // [0 1 2 3 4 5 6 7 8 9] len:10, cap:16, ptr:0xc000078000
Visible to the naked eye: slice numSlice automatically expands according to the rules of 1, 2, 4, 8, 16, twice as large as before each expansion
The append() function also supports appending multiple elements at once
func main() { var citySlice []string citySlice = append(citySlice, "Beijing") citySlice = append(citySlice, "Shanghai", "Guangzhou", "Shenzhen") a := []string{"Chengdu", "Chongqing"} citySlice = append(citySlice, a...) fmt.Println(citySlice) } // [Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Chongqing]
Tile Expansion Strategy
By looking at the $GOROOT/src/runtime/slice.go source, the code for expanding is as follows
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 } } }
- First, if the new application capacity (cap) is more than twice the old.cap, the final capacity (newcap) is the new application capacity (cap).
- Otherwise, if the length of the old slice is less than 1024, the final capacity (newcap) is twice that of the old.cap (newcap=doublecap).
- Otherwise, if the old slice length is greater than or equal to 1024, the final capacity (newcap) will increase by one-fourth from the old capacity (old.cap), i.e. (newcap=old.cap,for {newcap += newcap/4}) until the final capacity (newcap) is greater than or equal to the new requested capacity (cap), i.e. (newcap >= cap)
- If the cap calculation value overflows, the cap is the new application capacity (cap)
Copying slices using the copy() function
First: remember that slices are reference types
The copy() function built into the Go language quickly copies data from one slice into another slice space
func main() { // copy() copy slice a := []int{1, 2, 3, 4, 5} b := make([]int, 5, 5) copy(b, a) // Copy elements from slice a to slice b fmt.Println(a) fmt.Println(b) b[0] = 100 fmt.Println(a) fmt.Println(b) } // [1 2 3 4 5] // [1 2 3 4 5] // [1 2 3 4 5] // [100 2 3 4 5]
go Delete Slice Element
There is no specific way to delete elements in go, only by index
func main() { a := []int{0,1, 2, 3, 4, 5, 6, 7, 8, 9} // Delete elements with indexes of 2 to 4 a = append(a[:2], a[5:]...) fmt.Println(a) } // [0 1 5 6 7 8 9]
To remove an element indexed as index from slice a, do a = append(a[:index], a[index+1:]...)
func main() { a := make([]int, 5, 10) fmt.Println(a) for i := 0; i < 10; i++ { a = append(a, i) fmt.Println(a) } } // [0 0 0 0 0] // [0 0 0 0 0 0] // [0 0 0 0 0 0 1] // [0 0 0 0 0 0 1 2] // [0 0 0 0 0 0 1 2 3] // [0 0 0 0 0 0 1 2 3 4] // [0 0 0 0 0 0 1 2 3 4 5] // [0 0 0 0 0 0 1 2 3 4 5 6] // [0 0 0 0 0 0 1 2 3 4 5 6 7] // [0 0 0 0 0 0 1 2 3 4 5 6 7 8] // [0 0 0 0 0 0 1 2 3 4 5 6 7 8 9]