切片数组 - GO

Array of slices - GO

1)

对于下面的切片声明,

var a [][3]string

创建一个指向 3 个字符串数组的切片 (a),len(a) = 3cap(a) =3 但不是 cap(a) >= 3

a = make([][3]string, 5)

创建 5 个切片,其中每个切片(比如 a[0])指向 3 个字符串数组,len(a[0]) = 3cap(a[0]) = 3


2)

对于切片声明,

var b [][3][6]string

创建一个切片 (b),它指向 3 个数组,每个数组包含 6 个字符串,其中 len(b) = 3cap(b) =3

b = make([][3][6]string, 5)

创建 5 个切片,其中每个切片(比如 b[0])指向 3 个数组,每个数组包含 6 个字符串


在这两种情况下,制作切片后,我说,创建5个切片,


考虑到语法,下面是我的两个问题,

a = make([][3]string, 5)

我的问题:

1)

是否为 5 个切片,其中每个切片(a[0])是 3 个字符串的数组?

它是单个切片 (a) 指向 5 个数组,每个数组包含 3 个字符串吗?

2)

我如何知道元素的类型?切片还是数组?

1) 在这种情况下,必须谨慎使用 "array of" 术语。

2) 与 C

不同,GO 中没有涉及隐式指针

1) Considering the syntax,

a = make([][3]string, 5)

Is it 5 slices, where each slice(a[0]) is array of 3 strings?

or

Is it a single slice(a) pointing to 5 arrays of 3 strings each?

它是一个包含 5 个元素的切片,其中每个元素是一个包含 3 个字符串的数组。

2)

How do I know the type of an element? slice or array?

切片和数组是不同的类型。您不能将数组和切片互换地分配给同一个变量,因此,如果声明将其声明为数组,则它是一个数组;如果将其声明为切片,则它是切片。如果它在括号中有一个 number ([5]string) 它是一个数组,如果括号是空的 ([]string) 它是一个切片。

2) For slice declaration,

var b [][3][6]string

creates a single slice(b) that points to 3 arrays of 6 strings each, where len(b) = 3 and cap(b) =3

b = make([][3][6]string, 5)

creates 5 slices, where each slice(say b[0]) points to 3 arrays of 6 strings each

没有。以前的代码只是声明一个变量,它还没有保存切片。后面的代码创建 one 切片,其中包含 five 个元素。

切片和数组是两种不同的类型:内存中的数组是相同类型值的连续序列。在 Go 中,类型具有固定大小。例如在 C++ 和

中存在非常相同的概念
int x[5]; // C and C++
x [5]int  // Go

基本上是相同的东西(不是 100% 相同,因为 C 和 C++ 中的数组是 "second class citizens" 并且在一些地方表现得很奇怪,Go 在这方面更统一)。

Go 中的切片是数组一部分的 "view",并且或多或少等同于具有指向第一个元素的指针的 C++ 结构,一些使用的元素(相对于first) 和一些可用元素(相对于 first)

// 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) 中高效传递(独立于 size/capacity),您也可以在 O(1) 中获取切片的 sub-slice...请注意 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}}

虽然 yz in the playground 在使用 fmt.Println 时看起来是一样的 [[1, 2], [3, 4], [5, 6]],但它们是非常不同的类型,例如你可以用

添加一对新的 y
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 的元素(因为元素是数组)