切片数组 – GO

huangapple go评论77阅读模式
英文:

Array of slices - GO

问题

对于下面的切片声明,

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


对于切片声明,

var b [][3][6]string

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

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

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


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


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

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

我的问题:

是5个切片,其中每个切片(a[0])都是包含3个字符串的数组吗?

还是

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

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

1) 在这种情况下,必须谨慎使用"数组的"术语。

2) 与C语言不同,GO中没有隐式指针。

英文:

1)

For below slice declaration,

var a [][3]string

creates a single slice(a) that points to array of 3 strings, len(a) = 3 and cap(a) =3 but not cap(a) >= 3

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

creates 5 slices, where each slice(say a[0]) points to array of 3 strings, len(a[0]) = 3 and cap(a[0]) = 3


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


In both cases, after making slices, I said, creates 5 slices,


Considering the syntax, below are my two questions,

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

My question:

1)

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?

2)

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

1) In such scenarios, "array of" terminology has to be cautiously used.

2) There are no implicit pointers involved in GO unlike C

答案1

得分: 3

切片(slice)和数组(array)是两种不同的类型:在内存中,数组是一系列相同类型的连续值。在Go中,类型具有固定的大小。同样的概念也存在于C++中:

int x[5]; // C和C++
x [5]int  // Go

基本上是相同的(不完全相同,因为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)   // 一个包含3个包含2个整数的数组的切片

// 相同的内容(除了具体数值)
y := [][2]int{[2]int{1, 2},
              [2]int{3, 4},
              [2]int{5, 6}}

// 一个包含3个包含两个整数的切片的数组
z := [3][]int{[]int{1, 2},
              []int{3, 4},
              []int{5, 6}}

例如,当使用fmt.Println时,yz在输出上看起来是相同的[[1, 2], [3, 4], [5, 6]],但它们是非常不同的类型。例如,你可以向y添加一个新的键值对:

y = append(y, [2]int{7, 8})  // 现在为[[1, 2], [3, 4], [5, 6], [7, 8]]

而你可以增加z的第一个元素的长度:

z[0] = append(z[0], 99) // 现在为[[1, 2, 99], [3, 4], [5, 6]]

但你不能向z添加新元素(因为它是一个数组),也不能扩展y的元素(因为元素是数组)。

英文:

Slices and arrays are two different types: an array in memory is a contiguous sequences of values of the same type. In Go a type has a fixed size. The very same concept is present for example in C++ and

int x[5]; // C and C++
x [5]int  // Go

are basically the same thing (not 100% the same because arrays in C and C++ are "second class citizens" and behave strangely in a few places, Go is more uniform on that).

A slice in Go is instead a "view" of a portion of an array, and is more or less equivalent to a C++ structure with a pointer to the first element, a number of used elements (relative to first) and a number of available elements (relative to first)

// C++
template&lt;typename T&gt;
struct Slice {
    T *first;
    int size, capacity;
};
Slice&lt;int&gt; x{nullptr, 0, 0};

// Go
var x []int

The Make special function is able to create slices associated to newly created arrays, given size and optional capacity:

// C++
template&lt;typename T&gt;
Slice&lt;T&gt; make(int size, int capacity=-1) {
    if (capacity == -1) capacity = size;
    return Slice&lt;T&gt;{new T[capacity], size, capacity};
}

// Go
x := Make([]int, size, capacity)

Slices can be efficiently passed around in O(1) (independently on size/capacity) and you can also take a sub-slice of a slice in O(1)... note that Go is garbage collected, doing the same in C++ would require some extra work (for example also keeping a pointer to the original array object and its size in the slice).

You can of course have arrays of slices, slices of slices, slices of arrays and arrays of arrays. Note however that in Go Make is used only to create slices (and maps) not for arrays...

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}}

While for example both y and z in the playground would look the same [[1, 2], [3, 4], [5, 6]] when using fmt.Println, they are very different types, for example you can add a new pair to y with

y = append(y, [2]int{7, 8})  // now [[1, 2], [3, 4], [5, 6], [7, 8]]

and you can instead increase the length of first element of z with

z[0] = append(z[0], 99) // now [[1, 2, 99], [3, 4], [5, 6]]

but you cannot add new elements to z (it's an array) and you cannot extend an element of y (because elements are arrays)

答案2

得分: 2

1)考虑语法,

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

是5个切片,每个切片(a[0])都是一个包含3个字符串的数组吗?

还是一个单独的切片(a),指向5个包含3个字符串的数组?

答案是:它是一个包含5个元素的单独切片,每个元素都是一个包含3个字符串的数组。

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

切片和数组是不同的类型。你不能将数组和切片互相赋值给同一个变量,因此,如果声明将其声明为数组,则它是一个数组;如果将其声明为切片,则它是一个切片。如果方括号中有一个数字([5]string),则它是一个数组;如果方括号为空([]string),则它是一个切片。

3)对于切片声明,

var b [][3][6]string

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

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

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

不对。前面的代码只是声明了一个变量,它还没有持有一个切片。后面的代码创建了一个包含5个元素的切片。

英文:

> 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?

Its a single slice with 5 elements where each element is an array of 3 strings.

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

Slices and arrays are different types. You can not interchangeably assign arrays and slices to the same variable, hence if the declaration declares it as an array, its an array, if it declares it as a slice, its a slice. If it has a number in the brackets ([5]string) its an array, if the brackets are empty ([]string) its a slice.

> 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

No. Former code just declares a variable, it doesn't hold a slice yet. Latter code creates one slice with five elements.

huangapple
  • 本文由 发表于 2017年1月28日 14:49:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/41907150.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定