meaning
Slice is a special array. Is a reference to a contiguous fragment of an array, so a slice is a reference type. Slices can be part of an array or a subset of items identified by the start and end indexes. The slice is a bit like the pointer in C language. The pointer can perform operations, but the cost is that the memory operation is out of bounds. The slice increases the size based on the pointer and restricts the memory area corresponding to the slice. During the use of the slice, it is impossible to manually adjust the internal address and size of the slice, so the slice is safer and more powerful than the pointer.
definition
The slice definition is divided into three forms. Generate from array, generate from slice, and newly define a slice.
Three elements
1. Start position: the start position of the slice reference array.
2. Size: the number of elements in the slice. The size in the slice cannot exceed the capacity. You can use the len() function to count the size of the slice.
3. Capacity: the maximum number of elements that can be stored in the slice. If there is not enough space to accommodate enough elements, the slice will be dynamically "expanded", and the length of the new slice will change. Generally, the expansion of slices is twice the capacity before expansion. You can use the cap() function to count the slice capacity.
The difference between slice and array
- A slice is a continuous reference to an array. The initial position of the slice points to the memory address of the array. If the value of the slice changes, the corresponding value of the array will change accordingly.
- The length of the slice is dynamic and is essentially a variable dynamic array. The length of the array is determined when it is defined. The length of the array cannot be modified later.
- The length of the slice can be dynamically expanded [as mentioned above].
- The slice itself does not save data, it is only the representation of the underlying array. Any changes made to the slice are reflected in the underlying array.
package main import ( "fmt" ) func main() { numa := [3]int{78, 79, 80} nums1 := numa[:] nums2 := numa[:] fmt.Println("array before change 1", numa) nums1[0] = 100 fmt.Println("array after modification to slice nums1", numa) nums2[1] = 101 fmt.Println("array after modification to slice nums2", numa) }
// output array before change 1 [78 79 80] array after modification to slice nums1 [100 79 80] array after modification to slice nums2 [100 101 80]
When multiple slices share an underlying array, the changes of each slice will be reflected in the underlying array.
Sample code
// Defining slices through arrays var array1 = [3]int{1, 1, 3} fmt.Println("The elements of the array are:", array1) slice1 := array1[0:2] slice1[1] = 11111 fmt.Println("The elements of the array are:", array1)
// Output results The elements of the array are: [1 1 3] The elements of the array are: [1 11111 3] `` ## Slice definition classification ### Array generation slice #### Define syntax ```go slice[Starting position:End position]
1.slice: object representing slice. For example, if a slice is generated from an array, slice is the defined array name.
2. Starting position: starting from the subscript of an element in the array, starting from 0 by default.
3. End position: the end position of the slice. That is, the subscript position of an element of the array. It should be noted that the open interval is taken here. If you need to get the last element of the array, the end position is the length of the array + 1.
4. Length of slice: (end position of slice - start position of slice).
Sample code
// Defining slices through arrays array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} slice := array(0:5) // The print result is [A B C D E] // Create slices using make slice1 := make([]string, 2, 3) slice1[0] = "1" fmt.Println(slice1) slice2 := make([]string, 2, 3) fmt.Println(slice2) fmt.Println("The length of the slice is", len(slice1)) fmt.Println("The capacity of the slice is", cap(slice1)) // output [1 ] [ ] The length of the slice is 2 The capacity of the slice is 3
Slice index
1. The start position and end position of the slice are omitted. By default, it is intercepted from the start position of the array to the end position of the array + 1. The result is the same slice as the contents of the array, representing the original slice.
// Slice definitions omit start and end positions array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("Both the start and end positions are default",array[:]) // output Both the start and end positions are default [A B C D E F G H I G K L]
2. The start position and end position of the slice are not omitted. Cut according to the start position and end position.
// Neither the start position nor the end position is omitted array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} slice := array(0:5) // output [A B C D E]
3. The start position is omitted and the end position is not omitted. By default, the array is cut from the start position to the end position.
// The start position is omitted and the end position is not omitted array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} slice := array(:5) // output [A B C D E]
4. The starting position is not omitted and the ending position is omitted. By default, it is stolen from the specified starting position of the array to the last position of the array (array length + 1).
// The start position is not omitted and the end position is omitted array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("Default end position:",array[2:]) // The print result is Default end position: [C D E F G H I G K L]
5. The start position and end position of the slice cannot exceed the range of the array.
array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("section",array[-1:100]) // The print result is invalid slice index -1 (index must be non-negative)
6. The start position and end position of the slice are both 0, and an empty slice is obtained, indicating that the slice is empty. It is generally used for slice reduction.
// Both start and end positions are 0 array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("section",array[0:0]) // The print result is section: []
Direct declaration slice
In addition to generating slices from the original array or slice, you can also declare a new slice. Each type can have its slice type, representing a continuous collection of multiple elements of the same type. Therefore, the slice type can also be declared.
Define syntax
// It can also be in the form of an empty array var slice []type
1.slice is the name of the slice.
2.type is the data type of the slice.
Code example
// Declare an integer slice var slice1 []int // Initialize a slice var slice2 []int = []int{}
Using make to define slices
In addition to the above methods, if you need to create a slice dynamically, you can use the make() built-in function.
Define syntax
make([]type, size, cap)
1.type is the data type of the slice.
2.size is the size of the slice.
3.cap is the capacity of the slice.
The size of the slice cannot exceed the capacity. The capacity represents the maximum number of elements in the slice, and the size of the slice represents the actual number of elements. For example, 30 people can sit in a classroom. Now there are 10 people. Here, 10 means size and 30 means cap.
Code example
// Define slice slice1 := make([]string, 2, 3) slice1[0] = "1" fmt.Println(slice1) // Print the following results [1 ]
If the corresponding subscript is not assigned a value during slice copying, a value is assigned by default according to the data type. For example, slince1 defined above has two lengths, but only the value with subscript 0 is assigned. Therefore, the value with subscript 1 is assigned by default according to the string type of data type.
Common operation
Length calculation
The slice length is calculated using len().
// Calculate slice length slice1 := make([]string, 2, 3) fmt.Println("The length of the slice is", len(slice1)) // The print result is The length of the slice is 2
Capacity calculation
Slice capacity is calculated using cap().
// Calculate slice length slice1 := make([]string, 2, 3) fmt.Println("The length of the slice is", cap(slice1)) // The print result is The capacity of the slice is 3
Judge whether it is empty
In the chapter of creating variables, it is mentioned that if a variable is not given an initialization value when it is created, a nil value will be assigned by default during compilation. Therefore, a slice is judged to be empty and directly compared with nil.
// Judge empty slice slice3 := make([]string, 2, 3) if slice3 == nil { fmt.Println("slice3 It's an empty slice") } else { fmt.Println("slice3 Not an empty slice") } var slice4 []string if slice4 == nil { fmt.Println("slice4 It's an empty slice") } else { fmt.Println("slice4 Not an empty slice") }
// output slice3 Not an empty slice slice4 It's an empty slice
// Error presentation slice1 := make([]int, 2, 5) slice2 := make([]int, 2, 5) if slice1 == slice2 { fmt.Println("equal") } else { fmt.Println("Don't want to wait") }
// output slice1 == slice2 (slice can only be compared to nil)
When using make to create a slice, a slice with a length of 2 and a capacity of 3 is defined. Although the slice content is [], it actually has a value, just a null value. Slice is a dynamic structure, which can only be determined to be equal to nil, and cannot be determined to be equal to each other. After declaring a new slice, you can use the append() function to add elements to the slice.
Slice append
Additional definition
Use append() to dynamically add elements to the start position, end position or middle position of the slice.
Syntax format
append(slice, element)
1.slice, the slice to be added must be a slice.
2.element, the element added to the slice, which can be a single element, multiple elements or slices.
Tail append
// Append element at the start of slice var slice []int = []int {1,2,3} // Prints the length and capacity of the original slice fmt.Println("The original slice length and capacity are", len(slice), cap(slice)) // Append an element to the slice slice = append(slice, 1) fmt.Println(slice) // Append multiple elements to the back of the slice slice = append(slice, 6,7,8,9) fmt.Println(slice) // Print the length and capacity of the new slice fmt.Println("The new slice length and capacity are", len(slice), cap(slice))
// The printed contents are as follows: The original slice length and capacity were 3 [1 2 3 1] [1 2 3 1 6 7 8 9] The length and capacity of the new slice were 8 and 12, respectively
matters needing attention
1. Add elements at the end of the slice, which can only be a single element or multiple elements separated by ",", but not other data types.
2. If the capacity is insufficient when adding elements to the slice, the slice will expand automatically. The rule of automatic capacity expansion is a multiple of 2. The following code:
// Verify automatic expansion of additional elements of slice var numbers []int for i := 0; i < 10; i++ { numbers = append(numbers, i) fmt.Printf("len: %d cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers) }
// output len: 1 cap: 1 pointer: 0xc0420080e8 len: 2 cap: 2 pointer: 0xc042008150 len: 3 cap: 4 pointer: 0xc04200e320 len: 4 cap: 4 pointer: 0xc04200e320 len: 5 cap: 8 pointer: 0xc04200c200 len: 6 cap: 8 pointer: 0xc04200c200 len: 7 cap: 8 pointer: 0xc04200c200 len: 8 cap: 8 pointer: 0xc04200c200 len: 9 cap: 16 pointer: 0xc042074000 len: 10 cap: 16 pointer: 0xc042074000
Start position append
// Appends an element to the start of the slice var slice = []int {1,2,3} slice = append([]int {0}, slice...) // Add a slice with only 1 element at the beginning slice = append([]int {-3,-2,-1}, slice...) // Add a slice with multiple elements at the beginning fmt.Println(slice)
// output [-3 -2 -1 0 1 2 3]
1. Add an element at the beginning of the slice. Take the added element as the first parameter of append(), and the second parameter is the original slice. You need to add "..." after the original slice.
2. The first parameter of append() must be slice.
3. Adding elements at the beginning of the slice will generally lead to memory reallocation, and all existing elements will be copied once. Therefore, the performance of adding elements from the beginning of the slice is much worse than that of adding elements from the tail.
Middle position append
// Append an element to the middle of the slice var slice2 = []int {1,2,3,7,8,9} slice2 = append(slice2[0:3], append([]int {4,5,6},slice2[3:]...)...) fmt.Println(slice2)
// output [1 2 3 4 5 6 7 8 9]
1. Append elements to the middle of the slice. The basic format is append(a[:i], append([]int{x}, a[i:]...)...) / / insert x at the ith position
2. The second append call in each add operation will create a temporary slice, copy the contents of a[i:] to the newly created slice, and then append the temporarily created slice to a[:i].
copy
Definition of replication
The language's built-in function, copy(), can copy one array slice into another array slice. If the two array slices added are not the same size, they will be copied according to the number of elements of the smaller array slice.
copy( destSlice, srcSlice []T) int
Where srcSlice is the data source slice and destSlice is the copy target (that is, copy srcSlice to destSlice). The target slice must be allocated enough space to carry the number of copied elements, and the data types of the source and target must be consistent. The return value of copy() function represents the number of elements actually copied.
Sample code
slice1 := []int{1, 2, 3, 4, 5} slice2 := []int{5, 4, 3} copy(slice2, slice1) // Only the first three elements of slice1 will be copied to slice2 fmt.Println(slice2) // output [1 2 3]
slice1 := []int{1, 2, 3, 4, 5} slice2 := []int{5, 4, 3} copy(slice1, slice2) // Only the three elements of slice2 will be copied to the first three positions of slice1 fmt.Println(slice1) // output [5 4 3 4 5]
Although it is more direct to copy slice elements by loop, the built-in copy() function is more convenient to use. The first parameter of copy() function is the target slice to be copied, and the second parameter is the source slice. Two slices can share the same underlying array, and there is no problem even if there is overlap. The example code is as follows:
// Demonstrate slices by looping slice1 := make([]int, 2, 110) slice2 := make([]int, 2, 110) slice1[0] = 1 slice1[1] = 2 slice2[0] = 5 fmt.Println(slice1)// [1 2] fmt.Println(slice2)// [5 0] // Copy slice 1 to slice 2 for i := 0; i < 2; i++ { slice2[i] = slice1[i] } fmt.Println(slice2)// [1 2] // Copy slice 2 to slice 1 for i := 0; i < 2; i++ { slice1[i] = slice2[i] } fmt.Println(slice1)// [5 0]
Reference and copy
package main import "fmt" func main() { // Set the number of elements to 1000 const elementCount = 1000 // Pre allocate enough element slices srcData := make([]int, elementCount) // Assign slice value for i := 0; i < elementCount; i++ { srcData[i] = i } // Reference slice data refData := srcData // Pre allocate enough element slices copyData := make([]int, elementCount) // Copy data to a new slice space copy(copyData, srcData) // Modify the first element of the original data srcData[0] = 999 // Prints the first element of the reference slice fmt.Println(refData[0]) // Prints the first and last elements of the duplicate slice fmt.Println(copyData[0], copyData[elementCount-1]) // Copy original data from 4 to 6 (not included) copy(copyData, srcData[4:6]) for i := 0; i < 5; i++ { fmt.Printf("%d ", copyData[i]) } }
Execute line 8 of the logic and define that the total number of elements is 1000. In line 11, an integer slice with 1000 elements is pre allocated, which will be used as the original data. In lines 14 to 16, fill srcData with integer values from 0 to 999. In line 19, reference refData to srcData, and the slice will not copy elements because of the equal sign operation. In line 22, pre allocate the same type of slice copyData of the same size as srcData. Line 24, use the copy() function to copy the original data into the copyData slice space. In line 27, modify the first element of the original data to 999. Line 30, the first element of the reference data will change. Line 33, print the first data of the copied data. Since the data is copied, it will not change. Line 36, copy the local data of srcData to copyData. Lines 38 to 40 print the copyData element after copying the local data.
The copy of slices is another allocation in memory to allocate the allocated space to the target space. If the original space changes, the newly allocated space will not be affected. References to slices are affected.
Slice deletion
The slice itself does not have a delete function operation. You can only use the properties of the slice itself. There are three situations for deleting slices: deleting the beginning, deleting the end and deleting the middle.
Delete beginning
// Delete slice start element // 1. Using slice interception method slice = []int{1, 2, 3} slice = slice[1:] // Delete the first element slice = slice[N:] // Delete the first N elements // 2. Use the append() function in the slice slice = []int{1, 2, 3} slice = append(slice[:0], slice[1:]...) // Delete the first element slice = append(slice[:0], slice[N:]...) // Delete the first N elements // 3. Use the copy() function of the slice slice = []int{1, 2, 3} slice = slice[:copy(slice, slice[1:])] // Delete the first element slice = slice[:copy(slice, slice[N:])] // Delete the first N elements
Using the append() function, the data pointer is not moved, but the subsequent data is moved to the beginning. It can be completed in place with append (the so-called in place completion refers to the completion within the memory interval corresponding to the original slice data, which will not lead to the change of memory space structure).
Delete middle
// Delete middle slice = []int{1, 2, 3, ...} slice = append(slice[:i], slice[i+1:]...) // Delete the middle 1 element slice = append(slice[:i], slice[i+N:]...) // Delete the middle N elements slice = slice[:i+copy(slice[i:], slice[i+1:])] // Delete the middle 1 element slice = slice[:i+copy(slice[i:], slice[i+N:])] // Delete the middle N elements
Delete end
// Delete end slice = []int{1, 2, 3} slice = slice[:len(slice)-1] // Delete the last 1 element slice = slice[:len(slice)-N] // Delete N tail elements
Specify location
// Deletes the specified location of the slice seq := []string{"a", "b", "c", "d", "e"} // Specify delete location index := 2 // View the elements before and after the deletion position fmt.Println(seq[:index], seq[index+1:]) // Connect the elements before and after the deletion point seq = append(seq[:index], seq[index+1:]...) fmt.Println(seq)
sort
// Integer sort sli := []int{1, 5, 3, 4} sort.Ints(sli) for index, value := range sli { fmt.Println(index, value) } fmt.Println("---------------") // String sorting sliStr :=[]string{"lisi", "zhangsan", "bruce"} sort.Strings(sliStr) fmt.Println(sliStr) fmt.Println("---------------") // Floating point sort sliFloat := []float64{12.56, 12.12} sort.Float64s(sliFloat) fmt.Println(sliFloat)
// output 0 1 1 3 2 4 3 5 --------------- [bruce lisi zhangsan] --------------- [12.12 12.56]
iterator
Go language has a special keyword range, which can iterate each element in the slice with the keyword for, as shown below:
// Create an integer slice and assign a value slice := []int{10, 20, 30, 40} // Iterates over each element and displays its value for index, value := range slice { fmt.Printf("Index: %d Value: %d\n", index, value) } // output Index: 0 Value: 10 Index: 1 Value: 20 Index: 2 Value: 30 Index: 3 Value: 40