Article Directory
foreword
In the Go language, arrays and slices look similar, but in fact they have many differences. This article will talk about their differences.
Arrays and slices are two commonly used data structures. They can both be used to store a set of elements of the same type, but there are some important differences in the underlying implementation and usage.
The length of the array in Go is immutable, and Slice solves the demand for variable-length arrays. There are two main differences between them
array
An array is a collection of elements of the same data type. When defining an array, the length and element type need to be specified.
For example: [4]int represents an array containing four integers, and the size of the array is fixed. And the length is part of its type ([4]int and [5]int are different, incompatible types).
Array elements can be accessed by index, for example, the expression s[n] means to access the nth element, and the index starts from zero.
declaration and initialization
func main() {
var nums [3]int // 声明并初始化为默认零值
var nums1 = [4]int{
1, 2, 3, 4} // 声明同时初始化
var nums2 = [...]int{
1, 2, 3, 4, 5} // ...可以表示后面初始化值的长度
fmt.Println(nums) // [0 0 0]
fmt.Println(nums1) // [1 2 3 4]
fmt.Println(nums2) // [1 2 3 4 5]
}
function parameters
If an array is used as a parameter of a function, what is actually passed is a copy of the array, not a pointer to the array. This also means that modifying the elements of the array in the function will not affect the original array.
package main
import (
"fmt"
)
func Add(numbers [5]int) {
for i := 0; i < len(numbers); i++ {
numbers[i] = numbers[i] + 1
}
fmt.Println("numbers in Add:", numbers) // [2 3 4 5 6]
}
func main() {
// declare and initialize the array
var numbers [5]int
for i := 0; i < len(numbers); i++ {
numbers[i] = i + 1
}
Add(numbers)
fmt.Println("numbers in main:", numbers) // [1 2 3 4 5]
}
slice
The usage scenarios of arrays are relatively limited, and slices are more commonly used.
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 that has three properties: pointer, length and capacity.
- Pointer: Points to the first element that the slice can access.
- Length: the number of elements in the slice.
- Capacity: the number of elements between the start element of the slice and the last element of the underlying array.
The underlying source code is defined as follows:
type slice struct {
array unsafe.Pointer
len int
cap int
}
declaration and initialization
func main() {
var nums []int // 声明切片
fmt.Println(len(nums), cap(nums)) // 0 0
nums = append(nums, 1) // 初始化
fmt.Println(len(nums), cap(nums)) // 1 1
nums1 := []int{
1,2,3,4} // 声明并初始化
fmt.Println(len(nums1), cap(nums1)) // 4 4
nums2 := make([]int,3,5) // 使用make()函数构造切片
fmt.Println(len(nums2), cap(nums2)) // 3 5
}
function parameters
When a slice is used as a function parameter, unlike an array, if a function accepts a slice parameter, the changes it makes to the slice elements will be visible to the caller, similar to passing a pointer to the underlying array.
package main
import (
"fmt"
)
func Add(numbers []int) {
for i := 0; i < len(numbers); i++ {
numbers[i] = numbers[i] + 1
}
fmt.Println("numbers in Add:", numbers) // [2 3 4 5 6]
}
func main() {
var numbers []int
for i := 0; i < 5; i++ {
numbers = append(numbers, i+1)
}
Add(numbers)
fmt.Println("numbers in main:", numbers) // [2 3 4 5 6]
}
Look at the above example again, change the parameter from an array to a slice, and the modification in the Add function will affect the main function.
Summarize
Finally, to sum up, you can also answer this way during the interview:
- An array is a fixed-length data type whose length is determined at the time of definition and cannot be changed dynamically; a slice is a variable-length data type whose length can be empty when defined or an initial length can be specified.
- The memory space of an array is allocated at the time of definition, and its size is fixed; the memory space of a slice is dynamically allocated at runtime, and its size is variable.
- When an array is used as a function parameter, the function operates on a copy of the array and will not affect the original array; when a slice is used as a function parameter, the function operates on a reference to the slice, which will affect the original slice.
- Slices also have the concept of capacity, which refers to the allocated memory space.