Please pay attention to the public number: A row of boats, follow me to progress together.
Introduction: This paper mainly introduces the basic concepts, common methods and precautions of Go language array and slice.
An array of
The array declaration
Package main import "FMT" func main() {var a [5]int var b [3]int = [3]int{1, 3} C := [3]int{1,2,3} // declare an array and assign d := [...] Int {1,2,3} // declare an array, [... Represents the length of the array, which is determined by the number of elements in the array when it is initialized. Int {3:11,12,13} // declare and initialize an array, the first three digits are the default values, the next three digits are 11,12, 13 fmt.Printf("a = %+d \n", a) fmt.Printf("b = %+d \n", b) fmt.Printf("c = %+d \n", c) fmt.Printf("d = %+d \n", D) FMT.Printf("e = % d \n", e)} a = [+0 +0 +0 +0 +0] b = [+1 +2 +3] c = [+1 +2 +3] d = [+1 +2 +3] e = [+0 +0 +0 +11 +12 +13]Copy the code
An array is a fixed length, and its length is part of the array property, and does not change after it is declared.
Whether an array is comparable depends on whether its elements are comparable. If the elements in an array can be compared, we can directly compare the equality of two arrays with the == operator.
We can get the length of an array using len.
An array is a value type that copies the entire array when passed as a parameter to a function. Instead of using a large array as a function argument, we use the * address operator, which passes the address of the array as an argument to reduce the performance overhead of copying arrays.
There is no value or reference problem in the way of parameter passing in Go language. In Go language, the value or reference is passed, depending on whether the parameter itself is a numeric type or a reference type.
Voice-over: The reference types in Go are: slices, dictionaries, channels, functions, and so on.
Slice
Slice is a data structure unique to the Go language. A slice base must depend on an array and is a reference to contiguous fragments of that array. Slicing, however, is more flexible than arrays and can automatically expand as slicing elements increase.
Slice declaration:
All of the above methods of initializing arrays, excluding the [] middle length, can be used to declare slicing. In addition to the above methods, slicing also has the following declaration:
Package main import "FMT" func main() {arr := [5]int{1,2,3,4,5} C := arr[1:] // Omit := arr[1:] // omit := arr[1:] // omit := arr[1:] // omit := arr[1:] Make ([]int,5,10) e := make([]int,5,10) e := make([]int,5,10) F := make([]int,5) // make([]int,5) . The default is equal to the length of the section capacity FMT Printf (" \ n + a = % d ", a) FMT) Printf (" a + b = % d \ n ", b) FMT) Printf (" \ n + c = % d ", c) fmt.Printf("d = %+d \n", d) fmt.Printf("e = %+d \n", e) fmt.Printf("f = %+d \n", f) }Copy the code
A slice has two attributes: length and capacity. Length represents the number of elements currently stored in the slice, and capacity represents the maximum number of elements currently stored in the slice. When the number of elements inserted into the slice exceeds its capacity, the slice will expand.
Slice-related methods: Len () and cap() are used to obtain the length and capacity of slices respectively
Package main import "FMT" func main() {// make([]int,5,10) FMT.Printf("len = %+d \n", Printf("cap = % d \n", cap(a))} len = +5 cap = +10Copy the code
Append (): Appends the element copy() to the end of the slice; Copy the value of one slice to another
Package main import (" FMT ") func main() {s1 := make([]int,5,10) s1 = append(s1, 9,10,11) S2 := make([]int,len(s1),10) // make([]int,len(s1),10) Printf("s1 = %+d \n", s1) FMT.Printf("s2 = %+d \n", s2) FMT.Printf("s2 = %+d \n", s2) // Continue to add elements to s1, Printf("len(s1) = %+d \n", len(s1)) fmt.Printf("cap(s1) = %+d \n", cap(s1))} s1 = [+0 +0 +0 +0 +0 +9 +10 +11] s2 = [+0 +0 +0 +0 +0 +9 +10 +11] len(s1) = +11 cap(s1) = +20Copy the code
Copy (s2,s1) Copies the values of elements in S1 to S2. If S2 is less than S1, only elements in s2 are copied. When the number of elements added to S1 exceeds the capacity of S1, the slice expands. The action of slice expansion is not to change the original slice, but to generate a slice with a larger capacity, and copy the existing elements and the new elements into the new slice.
Slice capacity expansion policy: 1. If the newly applied capacity is more than twice the current capacity, the newly applied capacity is used. 2. If the new capacity is less than or equal to twice the current capacity, if the current capacity is less than 1024, the new capacity is twice the current capacity. If the current capacity is greater than 1024, add 1.25 times the current capacity and compare it with the new capacity until it is greater than the new capacity.
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.cap < 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
We verify that in the process of slice expansion, new slices are applied and the old slices remain unchanged.
Package main import (" FMT ""unsafe") func main() {s1 := []int{1,2,3,4,5} PTR := unsafe.pointer (&s1[0]) // Unsafe. Pointer (); fpt. Printf(" first element address = %+d \n", PTR); Printf("s1 [0] = % d \n", The unsafe. The Pointer (& s1 [0]) s: = (* int) (PTR) FMT. Printf (" s1 first element numerical + = % d ", * s)} the output: S1 Initial address of the first element =+ 824634318848 S1 Initial address of the first element =+ 824634351616 S1 Initial value =+1Copy the code
The memory address of the first element in s1 slice before and after expansion is different, so it can be determined that the two elements are not the same object. It can be determined that the value of the first element of S1 does not change after the expansion, and the expansion of slices does not modify the value of the original slice. If s1 is sliced and all elements are printed out before expansion, the value will remain the same.
Slice expansion has an easy pit point, see the code.
package main import "fmt" func main() { arr := [5]int{1, 2, 3, 4, 5} s1 := arr[0:2] s2 := append(s1, Printf(" s1 = %v, Pointer = %p, len = %d, cap = %d\n", s1, &s1, len(s1), Cap (s1)) fmt.Printf(" first print s2 = %v, Pointer = %p, len = %d, cap = %d\n", s2, &s2, len(s2), Cap (s2)) s2[1] += 50 FMT.Printf(" s1 = %v, Pointer = %p, len = %d, cap = %d\n", Cap (s1)) fmt.Printf(" Printf(s2 = %v, Pointer = %p, len = %d, cap = %d\n", s2, &s2, len(s2), Cap (s2)) fmt.Printf("arr = %v\n", arr)} Print s1 = [1 2], Pointer = 0xC000114000, Len = 2, cap = 5 print S2 = [1 2 100], Pointer = 0xC000114018, len = 3, Cap = 5 Print s1 = [1 52], Pointer = 0xC000114000, Len = 2, cap = 5 Print S2 = [1 52 100], Pointer = 0xC000114018, len = 3, cap = 5 arr = [1 52 100 4 5]Copy the code
From the result, we can see that changing the element value of slice S2 also changes the value of array ARr, because s1 refers to arR array, and all s1 values also change. In this case, because the array length is long enough, no new array will be applied after expansion, slice still points to the old array.
The source code for Go slices is in the Runtime slice. Go file.