Go has two confusing concepts: Array and Slice. This article will analyze the similarities and differences between the two data structures.

Array

Array in Go language is a collection of data. The capacity and initial value need to be specified in the declaration, and the length is fixed once the declaration, and the access is based on the index. Len is the built-in function to get the number of elements in the array.

Initialize the

Arrays must be initialized with a specified size and initial value, but the Go language gives us some more flexible ways to initialize them. For example, use… To automatically get the length; If no value is specified, 0 is used to give the initial value. Specifies the initial value of the specified element, etc. Here are some examples of how arrays can be initialized.

var arr [5]int	// Declare an array of size 5, default initialization value is [0,0,0,0]
arr := [5]int{1}	// declare and initialize the first element of an array of size 5 with the value [1,0,0,0,0]
arr := [...]int{1.2.3}	/ / by... Automatically gets the array length, initializes the size to 3 based on the number of values initialized, and initializes the value to [1,2,3].
arr := [...]int{4:1}	// Specify the value of element 4 as 1 by... The automatic acquisition length is 5, and the value after initialization is [0,0,0, 1].
Copy the code

Function parameters

When the array is used as a function parameter, the size of the array must be specified, and the size of the array passed must be the same as the specified size. The array is passed by value, and the change of the array value in the function does not affect the initial array:

package main

import "fmt"

//PrintArray print the value of array
func PrintArray(arr [5]int) {
    arr[0] = 5
	fmt.Println(arr)
}

func main(a) {
	a := [...]int{4:1}
	PrintArray(a)	/ /,0,0,0,1 [5]
    fmt.Println(a)	/ /,0,0,0,1 [0]
}
Copy the code

Slice

Slice is one of the most important data types in the Go language. It can be understood as an array of dynamic length (although Slice actually contains an array) and can be accessed as an array or through slicing operations. Slice has three properties: pointer, length, and capacity. Pointers are Slice names that point to the first element in the array that Slice can access. The length refers to the number of elements in the current slice and cannot exceed the slice capacity. The capacity is the maximum number of elements slice can contain, but in practice it is automatically expanded to twice that amount when the capacity is insufficient. The length and size of slice can be obtained using the built-in functions Len and CAP.

Initialize the

Slice initializes Pointers, length, and capacity, which are automatically initialized to the size of the length when not specified. Arrays can be initialized by directly getting a reference to an array, by getting a slice of an array /slice, or by the make function. Here are some examples of how slice can be initialized.

s := []int{1.2.3}	// initialize by reference to an array with a value of [1,2,3] and length and capacity of 3

arr := [5]int{1.2.3.4.5}
s := arr[0:3]	// initialize through a slice of the array with a value of [1,2,3], length of 3, and capacity of 5

s := make([]int.3)	// initialize with the make function with a value of [0,0,0] and a length and capacity of 3

s := make([]int.3.5)	// initialize with make, value [0,0,0], length 3, capacity 5
Copy the code

One particular concern is initialization by slicing. If a slice is initialized by a slice, the structure of the initialized slice actually looks like the following:

The values of x are [2,3,5,7,11] and the values of y are [3,5,7], and the Pointers to both slices point to the same array, meaning that changing the values of the elements in x will cause the values in y to change as well.

Such initialization may cause memory to be corruptedExcessive consumptionFor example, you only need to use a few elements in a very large array, but because you need to point to the entire array, the entire array cannot be freed during GC. Therefore, it is best to use slice operation for initializationappendThe slicing function copies the sliced data into a new slice, avoiding the memory footprint trap.

Function parameters

In Go, Slice is passed by reference as a function parameter. Changes to elements in the function cause changes to values outside the function, but since the function is passed a copy of a pointer, So modifications to this pointer do not change the original pointer (for example, the append function does not change the value of the original slice). For details, see the following code:

package main

import "fmt"

//PrintSlice print the value of slice
func PrintSlice(s []int) {
	s = append(s, 4)
	s[0] = - 1
	fmt.Println(s)
}

func main(a) {
	s := []int{1.2.3.4.5}
	s1 := s[0:3]

    fmt.Println("s:",s)	/ / s: [1, 2, 3, 4, 5]
    fmt.Println("s1:",s1)	/ / s1: [1, 2, 3]
	PrintSlice(s1)	/ / [1, 2, 3, 4]
	fmt.Println("s:",s)	/ / [1, 2, 3, 4, 5]
	fmt.Println("s1:",s1)	/ / [1, 2, 3]
}
Copy the code

conclusion

  • The length of the array cannot be changed, it is fixed after initialization; The length of the slice is not fixed, and elements can be added, which may increase the capacity of the slice.
  • The structure is different. An array is a string of fixed data, while slicing describes intercepting part of the data of the array, which is a structure in concept.
  • The initialization methods are different, as shown above. In addition, when declaring an array, square brackets indicate the length or use of the array.Automatically calculates the length while declaringslice, there are no characters in square brackets.
  • Sizeof (slice) returns the sizeof the slice descriptor, regardless of the number of elements in the slice, and returns 24 bytes of data. Unsafe.sizeof (arr), which increases with the number of arr elements, is the sizeof the data stored in the array.
  • Function calls are passed differently, with arrays passed by value and slices passed by reference.