Arrays have a fixed length and are part of a type, so they have a lot of 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}
Copy the code
We already have three elements in array A, so we can’t add any more elements to array A.
slice
A Slice is a variable-length sequence of elements of the same type. It is a layer of encapsulation based on the array type. It is very flexible and supports automatic expansion.
A slice is a reference type whose internal structure contains an address, length, and capacity. Slicing is generally used to quickly manipulate a collection of data.
Definition of slice
The basic syntax for declaring slice types is as follows:
var name []T
Copy the code
Among them,
- Name: indicates the variable name
- T: indicates the element type in the slice
Here’s an example:
Var b = []int{} // Declare an integer slice and initialize var c = []bool{false, Var d = []bool{false, // Declare a Boolean slice and initialize 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, can not support direct comparison, can only compare with nil}Copy the code
Length and capacity of slice
Slices have their own length and capacity. We can calculate the length of slices by using the built-in len() function and the capacity of slices by using the built-in cap() function.
Slice expression
A slice expression constructs a substring or slice from a string, array, or pointer to an array or slice. It comes in two variants: a simple form that specifies low and high index bounds, and a full form that specifies capacity in addition to low and high index bounds.
Simple slice expression
The bottom layer of a slice is an array, so we can get a slice based on an array through a slice expression. Low and high in the slice expression represent an index range (left included, right excluded), that is, in the following code, elements 1<= index value <4 from array A are selected to form slice S, the length of the slice obtained is =high-low, and the capacity is equal to the capacity of the underlying array of the slice obtained.
func main() {
a := [5]int{1, 2, 3, 4, 5}
s := a[1:3] // s := a[low:high]
fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
}
Copy the code
Output:
s:[2 3] len(s):2 cap(s):4
Copy the code
For convenience, you can omit any indexes in the slice expression. Omitting low defaults to 0; Omitting high defaults to the length of the slice operand:
A [2] / / is equivalent to a [2: len (a)] [3] / / a is equal to a [3-0] a [:] / / is equivalent to a [0: len (a)]Copy the code
Note: For arrays or strings, the index is valid if 0 <= low <= high <= len(a), otherwise the index is out of range.
When the slice expression is executed for the slice again (slice again slice), the upper bound of high is the capacity cap(a) of the slice, not the length. A constant index must be non-negative and can be represented by a value of type int; For arrays or constant strings, the constant index must also be in a valid range. If both low and high are constants, they must satisfy low <= high. A runtime panic occurs if the index is out of range at run time.
func main() { a := [5]int{1, 2, 3, 4, 5} s := a[1:3] // s := a[low:high] fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, Len (s), cap (s)) s2: = s [did] / / index of cap cap (s) is not len (s) FMT. Printf (" s2: % v len (s2) : % v cap (s2) : % v \ n ", s2, len (s2), cap(s2)) }Copy the code
Output:
s:[2 3] len(s):2 cap(s):4
s2:[5] len(s2):1 cap(s2):1
Copy the code
Complete slice expression
For arrays, Pointers to arrays, or slice a(not strings) support full slice expressions:
a[low : high : max]
Copy the code
The above code constructs a slice of the same type, length, and elements as the simple slice expression A [low: high]. In addition, it sets the capacity of the resulting slice to max-low. Only the first index value (low) can be omitted in the full slice expression; It defaults to 0.
func main() {
a := [5]int{1, 2, 3, 4, 5}
t := a[1:3:5]
fmt.Printf("t:%v len(t):%v cap(t):%v\n", t, len(t), cap(t))
}
Copy the code
Output result:
t:[2 3] len(t):2 cap(t):4
Copy the code
The conditions for a complete slice expression are 0 <= low <= high <= Max <= cap(a), and other conditions are the same as those for a simple slice expression.
Use the make() function to construct slices
If you want to create a slice dynamically, you need to use the built-in make() function, which has the following format:
make([]T, size, cap)
Copy the code
Among them:
- T: the element type of the slice
- Size: the number of elements in the slice
- Cap: indicates the slice capacity
Here’s an example:
func main() {
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 nature of slices
The essence of slicing 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:
Determine whether the slice is empty
To check if the slice is empty, always use len(s) == 0 and should not use s == nil.
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! =nilCopy the code
Therefore, to determine whether a slice is empty, len(s) == 0 should not be used to determine s == nil.
An assigned copy of a 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.
Func main() {s1 := make([]int, 3) //[0 0 0] s2 := s1 Println(s1) //[100 00] Println(s2) //[100 00]}Copy the code
Slice traversal
Slice traversal is the same as array traversal, supporting index traversal and for range traversal.
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)
}
}
Copy the code
The append() method adds elements to the slice
The Go language’s built-in function Append () can dynamically add elements to slices. You can add one element at a time, you can add multiple elements, or you can add elements from another slice (followed by…). .
func main(){ var s []int s = append(s, 1) // [1] s = append(s, 2, 3, 4) // [1 2 3 4] s2 := []int{5, 6, 7} s = append(s, s2...) // [1 2 3 4 5 6 7]}Copy the code
Note: A zero-value slice declared by var can be used directly in the append() function without initialization.
var s []int
s = append(s, 1, 2, 3)
Copy the code
There is no need to initialize a slice and pass it into the append() function as shown below,
Var s = make([]int) // appEnd (s, 1, 2, 3)Copy the code
Each slice points to an underlying array, and when the array is large enough, new elements are added. 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 “expansion” operation usually occurs when the append() function is called, so we usually need to receive the return value of the Append function in the original variable.
Here’s an example:
Func main() {//append() 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
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:0xc0000b8000Copy the code
As can be seen from the above results:
append()
The function appends the element to the end of the slice and returns the slice.- The capacity of numSlice is automatically expanded according to the rule 1,2,4,8,16. After each expansion, the capacity is doubled.
The append() function also supports appending multiple elements at once. Such as:
Var citySlice []string citySlice = AppEnd (citySlice, "Beijing ") var citySlice = Append (citySlice," Shanghai ") "Guangzhou", "shenzhen") / / additional section a: = [] string {" chengdu ", "chongqing"} citySlice = append (citySlice, a...). Println(citySlice) //[Beijing Shanghai Guangzhou Shenzhen Chengdu Chongqing]Copy the code
Slice capacity expansion policy
Can see $GOROOT/SRC/runtime/slice. Go source, expansion and the relevant code 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
}
}
}
Copy the code
From the code above you can see the following:
- First, if the new applied capacity (CAP) is greater than twice the old capacity (old.cap), the final capacity (NewCap) is the new applied capacity (CAP).
- Otherwise, if the length of the old slice is less than 1024, the final capacity (newcap) is twice that of the old capacity (old.cap), i.e. (newCap = Doublecap),
- Otherwise, if the length of the old slice is greater than or equal to 1024, then the final capacity (newcap) increases by 1/4 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 capacity (CAP), i.e. (newCap >= CAP)
- If the calculated final capacity (CAP) overflows, the final capacity (CAP) is the new applied capacity (CAP).
It should be noted that slice expansion also performs different processing according to the type of elements in the slice. For example, the processing method of int and string types is different.
Use the copy() function to copy slices
Let’s start with a question:
func main() {
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:
copy(destSlice, srcSlice []T)
Copy the code
Among them:
- SrcSlice: indicates the slice of data source
- DestSlice: indicates the destination slice
Here’s an example:
Func main () {/ / copy (copy) section a: = int [] {1, 2, 3, 4, 5} c: = make (int [], 5, 5) copy (c, 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] c[0] = 1000 fmt.println (a) //[1 2 3 4 5] fmt.Println(c) //[1000 2 3 4 5] }Copy the code
Deletes 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() {// delete element a := []int{30, 31, 32, 33, 34, 35, 36, 37} // delete element A = append(a[:2], a[3:]... fmt.Println(a) //[30 31 33 34 35 36 37] }Copy the code
A = append(a[:index], a[index+1:]…)