切片和数组是两种不同的类型:内存中的数组是相同类型值的连续序列。在 Go 中,类型具有固定大小。例如,在 C++ 和
中存在完全相同的概念
int x[5]; // C and C++
x [5]int // Go
基本上是相同的(不是 100% 相同,因为 C 和 C++ 中的数组是“二等公民”并且在一些地方表现得很奇怪,Go 在这方面更加统一)。
Go 中的切片是数组一部分的“视图”,它或多或少等价于 C++ 结构,其中包含指向第一个元素的指针、许多使用的元素(相对于第一个元素)和一个可用元素的数量(相对于第一个)
// C++
template<typename T>
struct Slice {
T *first;
int size, capacity;
};
Slice<int> x{nullptr, 0, 0};
// Go
var x []int
Make 特殊函数能够创建与新创建的数组关联的切片,给定大小和可选容量:
// C++
template<typename T>
Slice<T> make(int size, int capacity=-1) {
if (capacity == -1) capacity = size;
return Slice<T>{new T[capacity], size, capacity};
}
// Go
x := Make([]int, size, capacity)
切片可以在 O(1) 中有效地传递(独立于大小/容量),您还可以在 O(1) 中获取切片的子切片...请注意,Go 是垃圾收集的,执行在 C++ 中同样需要一些额外的工作(例如,还要保留指向原始数组对象的指针及其在切片中的大小)。
您当然可以有切片数组、切片切片、数组切片和数组数组。但是请注意,在 Go 中 Make 仅用于创建切片(和映射)而不是用于数组...
x := Make([][2]int, 3) // a slice of 3 arrays of 2 ints each
// Same thing (except for content)
y := [][2]int{[2]int{1, 2},
[2]int{3, 4},
[2]int{5, 6}}
// An array of 3 slices of two ints each
z := [3][]int{[]int{1, 2},
[]int{3, 4},
[]int{5, 6}}
虽然y 和z in the playground 在使用fmt.Println 时看起来相同[[1, 2], [3, 4], [5, 6]],但它们是非常不同的类型,例如您可以使用
y = append(y, [2]int{7, 8}) // now [[1, 2], [3, 4], [5, 6], [7, 8]]
您可以改为增加z 的第一个元素的长度
z[0] = append(z[0], 99) // now [[1, 2, 99], [3, 4], [5, 6]]
但是你不能向z添加新元素(它是一个数组),你不能扩展y的元素(因为元素是数组)