Go language slice (Slice)
Go slicing is an abstraction of arrays.
The length of Go array cannot be changed, and such a collection is not very suitable in specific scenarios. Go provides a flexible and powerful built-in type slice ("dynamic array"). Compared with arrays, the length of the slice is not fixed. Elements can be added, which may increase the capacity of the slice when appending.
Declare Slice
A slice with a T type element is represented by []T, where T represents the type of the element in the slice. Slices can be represented internally by a structure type, in the form as follows:
type slice struct { Length int Capacity int ZerothElement *byte }
It can be seen that a slice consists of three parts: pointer, length and capacity. The pointer points to the address of the underlying array element corresponding to the first slice element. The length corresponds to the number of elements in the slice; the length cannot exceed the capacity, and the capacity is generally from the start position of the slice to the end position of the underlying data. The length and capacity of slice are returned by the len and cap functions respectively.
Create a Slice
Declare creation slice directly
[]<Element type>{element1, element2, …}
Create an array with 3 integer elements and return a slice reference stored in c.
c := []int{6, 7, 8}
Make() function creates slice
s1 := make([]int, 5) //Length and capacity are 5 s2 := make([]int, 3, 10) //Length is 3 and capacity is 10 (cap(s1),s2)
Create based on the underlying array or slice
Create based on existing slices or arrays, just use operators like [i:j]. It means that it starts with the i index and ends with the j index, intercepts the original array or slice, and creates a new slice. The value of the new slice contains the i index of the original slice, but does not contain the j index. Note that neither i nor j can exceed the index of the original slice or array
slice :=[]int{1,2,3,4,5} slice1 := slice[:] slice2 := slice[0:] slice3 := slice[:5] (slice1) (slice2) (slice3)
The new slice and the original array or the original slice share a bottom array, so when modified, the value of the bottom array will be changed, so the value of the original slice will also change.
slice := []int{1, 2, 3, 4, 5} newSlice := slice[1:3] newSlice[0] = 10 (slice) (newSlice)
The difference between slices and arrays
1. Slices are not arrays, but the bottom layer of slices points to arrays
2. The length of the slice itself is not certain, so it cannot be compared, and arrays are OK.
3. Slices are an alternative to variable-length arrays that can be associated to local or all of the underlying arrays pointed to.
4. Slices are reference passing (passing pointer address), while arrays are value passing (copy value)
5. Slices can be created directly, referring to other slices or arrays.
6. If multiple slices point to the same underlying array, modification of one of the values will affect all slices
Modification of slices
The slice itself does not own any data. It is just a representation of the underlying array. Any modifications made to the slice are reflected in the underlying array.
package main import ( "fmt" ) func main() { arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} slice := arr[2:5] ("array before", arr) for i := range slice { slice[i]++ } ("array after ", arr) }
In line 9 of the above program, we create a slice dslice based on array index 2,3,4. The for loop increments the values in these indexes one by one. When we use for loop to print the array, we can see that changes to the slice are reflected in the array. The output of this program is
array before [0 1 2 3 4 5 6 7 8 9] array after [0 1 3 4 5 5 6 7 8 9]
When multiple slices share the same underlying array, the changes made by each slice are reflected in the array.
package main import ( "fmt" ) func main() { array := [4]int{10, 20 ,30, 40} slice1 := array[:] slice2 := array[:] ("array before change:", array) slice1[0] = 60 ("array after modification to slice slice1:", array) slice2[1] = 70 ("array after modification to slice slice2:", array) }
In 9 lines, numa [:] lacks the start and end values. The default values for start and end are 0 and len (numa) respectively. Two slices nums1 and nums2 share the same array. The output of this program is
array before change: [10 20 30 40] array after modification to slice slice1: [60 20 30 40] array after modification to slice slice2: [60 70 30 40]
It is clear from the output that when the slices share the same array, each modification is reflected in the array.
Length and capacity of slices
The length of the slice is the number of elements in the slice. The capacity of a slice is the number of elements in the underlying array starting from the creation of the slice index.
package main import ( "fmt" ) func main() { fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"} fruitslice := fruitarray[1:3] ("length of slice %d capacity %d", len(fruitslice), cap(fruitslice)) // length of is 2 and capacity is 6 }
In the above program, fruitslice is created from indexes 1 and 2 of fruitarray. Therefore, the length of fruitlice is 2 .
The length of fruitarray is 7. fruitslice is created from index 1 of fruitarray. Therefore, the capacity of fruitslice starts with the fruitarray index of 1, that is, starting with orange, the value is 6. Therefore, fruitslice has a capacity of 6. This program] output slice length is 2 and capacity is 6.
The slice can reset its capacity. Anything beyond this will cause an error to be thrown when the program is running.
package main import ( "fmt" ) func main() { fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"} fruitslice := fruitarray[1:3] ("length of slice %d capacity %d\n", len(fruitslice), cap(fruitslice)) // length of is 2 and capacity is 6 fruitslice = fruitslice[:cap(fruitslice)] // re-slicing furitslice till its capacity ("After re-slicing length is",len(fruitslice), "and capacity is",cap(fruitslice)) }
In line 11 of the above program, the capacity of fruitslice is reset. The above program output is,
length of slice 2 capacity 6 After re-slicing length is 6 and capacity is 6
Append slice elements
As we already know that the length of an array is fixed, its length cannot be increased. Slices are dynamic, and using append to append new elements to slices. The append function is defined as
func append(s[]T,x ... T)[]T
Append can directly append elements at the end of the slice, or append one slice to the end of another slice.
package main import ( "fmt" ) func main() { str := []string{"a", "b", "c"} ("strs:", str, " length:", len(str), "capacity:", cap(str)) str = append(str, "d") ("strs:", str, " length:", len(str), " capacity:", cap(str)) }
In the above program, the capacity of str is initially 3. On line 10, we add a new element to str and assign the slice returned by append(str, "d") to str. Now str's capacity doubled and turned into 6.
strs: [a b c] length: 3 capacity: 3 strs: [a b c d] length: 4 capacity: 6
The zero value of slice type is nil. The length and capacity of a nil slice are 0. The append function can be used to append values to nil slices.
package main import ( "fmt" ) func main() { var strs []string //zero value of a slice is nil if strs == nil { ("slice is nil going to append") strs = append(strs, "a", "b", "c") ("string contents:",strs) } }
In the above program names are nil, we have added 3 strings to names . The output of this program is
slice is nil going to append string contents: [a b c]
You can also use the ... operator to add one slice to another.
package main import ( "fmt" ) func main() { veggies := []string{"potatoes", "tomatoes", "brinjal"} fruits := []string{"oranges", "apples"} food := append(veggies, fruits...) ("food:",food) }
On line 10 of the above program, food is passedappend(veggies, fruits...)
create. The output of the program isfood: [potatoes tomatoes brinjal oranges apples]
。
It is particularly important to note that if the length of the new slice does not exceed the capacity of the source slice, the source slice will be returned. If the length of the appended new slice exceeds the capacity of the source slice, a brand new slice will be returned.
func main() { s1 := []int{1,2,3,4,5} ("s1:%p %d %d %v\n",s1,len(s1),cap(s1),s1) s2 :=append(s1,6) ("s3:%p %d %d %v\n",s2,len(s2),cap(s2),s2) s3 := s1[0:4] ("s3:%p %d %d %v\n",s3,len(s3),cap(s3),s3) s4 := append(s3,6) ("s4:%p %d %d %v\n",s4,len(s4),cap(s4),s4) ("s1:%p %d %d %v\n",s1,len(s1),cap(s1),s1) s5 := append(s4,8) ("s5:%p %d %d %v\n",s5,len(s5),cap(s5),s5) }
Function passing of slices
A slice contains length, capacity, and a pointer to the zeroth element of the array. When a slice is passed to a function, the pointer variable will reference the same underlying array even if it is passed through the value. Therefore, when a slice is passed to a function as an argument, the changes made within the function are also visible outside the function.
package main import ( "fmt" ) func subtactOne(numbers []int) { for i := range numbers { numbers[i] -= 2 } } func main() { nos := []int{8, 7, 6} ("slice before function call", nos) subtactOne(nos) // function modifies the slice ("slice after function call", nos) // modifications are visible outside }
In line number 17 of the above program, the call function decrements each element in the slice by 2. These changes are visible when printing slices after function calls. If you remember, this is different from arrays, and changes to an array in a function are not visible outside the function.
array before function call [8 7 6] array after function call [6 5 4]
Multidimensional slices
Similar to an array, slices can have multiple dimensions.
package main import ( "fmt" ) func main() { pls := [][]string { {"C", "C++"}, {"JavaScript"}, {"Go", "Rust"}, } for _, v1 := range pls { for _, v2 := range v1 { ("%s ", v2) } ("\n") } }
The output of the program is,
C C++ JavaScript Go Rust copy
The slice holds a reference to the underlying array. As long as the slice is in memory, the array cannot be garbage collected. In terms of memory management, this is something to be paid attention to. Let's assume we have a very large array and we want to handle only a small part of it. Then, we create a slice from this array and start processing the slice. It is important to note here that the array is still in memory when the slice reference is referenced.
One solution is to use the copy function to generate a copy of a slice. This way we can use new slices and the original array can be garbage collected.
func copy(dst,src[]T)int` package main import ( "fmt" ) func main() { s1 :=[]int{1,2,3,4,5} ("s1",s1) s2 := make([]int,len(s1)) ("s2",s2) copy(s2,s1) ("s2",s2) s3 :=make([]int,len(s1)-2) copy(s3,s1); ("s3",s3) s4 :=make([]int,len(s1)-1) copy(s4[1:3],s1[2:4]); ("s4",s4) }
Print result:
s1 [1 2 3 4 5] s2 [0 0 0 0 0] s2 [1 2 3 4 5] s3 [1 2 3] s4 [0 3 4 0]
Summarize
The above is a detailed explanation of the Go basic Slice tutorial introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support for my website!