When I was learning the fundamentals of Go, I was surprised to find that Go does not have rich built-in libraries around the collections such as Arrays, Maps, etc.. One reason is that coming from the traditional languages like Java, I was familiar with several implementations of Array and Map types. For example, there is a rich collection of LinkedLists, ArrayLists, HashMap, LinkedHashMap, etc. in Java. Soon, I’ve realized that with the built-in Arrays, Slices, and Maps in Go, one can get most of the stuff done with ease. But yes, there is a learning curve involved to get a deeper understanding of the concepts around Arrays, Slices, and Maps. Here in this article, I’d detail the basics and usage of the types — Arrays and Slices.
当我学习Go的基础知识时,我惊讶地发现Go周围没有诸如Arrays,Maps等集合的丰富内置库。原因之一是来自Java之类的传统语言,熟悉Array和Map类型的几种实现。 例如,在Java中有丰富的LinkedLists,ArrayLists,HashMap,LinkedHashMap等集合。 很快,我意识到使用Go中的内置Array,Slice和Maps,可以轻松完成大部分工作。 但是,是的,要深入了解数组,切片和贴图的概念,需要学习一条曲线。 在本文的此处,我将详细介绍类型(数组和切片)的基本知识和用法。
Arrays
数组
Almost all of the mainstream languages have Arrays. An Array is an indexed list of some type. Arrays have a fixed size and we provide it during the initialization. The indexing of elements in the array starts with zero. An array of strings is initialized in one of the two was below —
几乎所有主流语言都有数组。 数组是某种类型的索引列表。 数组有固定的大小,我们在初始化时提供。 数组中元素的索引从零开始。 在下面的两个之一中初始化了一个字符串数组-
length of array-1 array[4]
length of array-1length of array-1array[4]
invalid array index 4 (out of bounds for 3-element array)
So it means that once an Array is defined, there is no way of adding it ie. an Array is a fixed list of elements. But in most of the cases, a feature to resize the list comes in handy. This is where Slices comes into the picture.
因此,这意味着一旦定义了数组,就无法添加它。 数组是元素的固定列表 。 但是在大多数情况下,调整列表大小的功能非常有用。 这是切片进入图片的地方。
Slices
切片
A slice is a chunk of an Array. Slices hold a reference to an underlying array. They are resizable ie. one can append elements or delete the existing ones. Slices do not hold data, they just hold pointers to an array of elements. A Slice is created as below —
切片是数组的一部分。 切片包含对基础数组的引用。 它们是可调整大小的,即。 一个可以追加元素或删除现有元素。 切片不保存数据,它们仅保存指向元素数组的指针。 切片如下创建—
array[startIndex : endIndex]startIndexendIndex[“World”, “!”]
array[startIndex : endIndex]startIndexendIndex[“World”, “!”]
In simpler terms, a Slice can be understood as a struct type like below -
简单来说,Slice可以理解为以下结构类型-
While the meaning of the name, type, pointer reference, and length is inferrable, capacity is a bit tricky. The Capacity of the slice refers to the number of elements that the upholding array has in it from the starting position of the slice. For example, consider the following scenario —
尽管名称,类型,指针引用和长度的含义是无法推断的,但是容量却有些棘手。 切片的容量是指从切片的起始位置开始,支持数组中包含的元素数。 例如,考虑以下情形:
As the above slice starts at index 2 and ends at 4, it’s length is 3. As the length of the upholding array is 10 and the starting index of the slice is 2, the capacity of the slice would be the number of elements from index position 2 to the end of the array ie. 10–2 = 8.
由于上面的切片从索引2开始并在4结束,所以它的长度是3。由于保持数组的长度是10,切片的起始索引是2,因此切片的容量将是索引中元素的数量位置2到数组的末尾,即 10–2 = 8。
The output of the above snippet is this -
上面的代码段的输出是-
slice: [3 4 5] has length: 3 , and capacity: 8
len()cap()
len()cap()
make()
make()
make([]int, 5)
intint[0 0 0 0 0]
intint[0 0 0 0 0]
append()
附加()
One way of realizing the flexibility feature of slices is through the built-in append function. Consider this scenario —
实现切片的灵活性功能的一种方法是通过内置的append函数。 考虑这种情况-
slice: [3 4 5] has length: 3 , and capacity: 4
slice: [3 4 5 9] array: [1 2 3 4 5 9]
[3 4 5 9]
[3 4 5 9]
Let us find out. I’m adding the below snippet to the above code.
让我们找出答案。 我将以下代码段添加到上面的代码中。
slice: [3 4 5 9 11] array: [1 2 3 4 5 9]
As expected, 11 is added to the slice. There is no surprise at this point. But interestingly, there is no update to the array. What happened internally is that as Array is a fixed chunk of elements and the capacity is exhausted, Go copied the elements of the array into a new array with double of the existing capacity and pointed the slice to this new array. We can verify this by calling cap() on the slice.
如预期的那样,将11添加到切片。 这并不奇怪。 但有趣的是,没有更新该阵列。 内部发生的情况是,由于Array是固定的元素块并且容量已用尽,因此Go 将数组的元素复制到具有现有容量两倍的新数组中, 并将切片指向该新数组 。 我们可以通过在切片上调用cap()来验证这一点。
and the output looks as below —
输出看起来如下:
slice: [3 4 5 9] array: [1 2 3 4 5 9]
capacity of the slice: 4
slice: [3 4 5 9 11] array: [1 2 3 4 5 9]
capacity of the slice: 8
array
array
make()
使()
make()make()lengthcapacity
make()make()lengthcapacity
append()slice[index]
append()slice[index]
The second argument is the length of the slice. In addition, we can provide capacity as well. Let us see, how the capacity of the slice changes as the length of the slice increases.
第二个参数是切片的长度。 另外,我们也可以提供能力。 让我们看看,切片的容量如何随切片长度的增加而变化。
Iteration
迭代
for
for
Accessing an index that is greater than the length of the slice would lead to error like below —
访问大于切片长度的索引将导致如下错误:
panic: runtime error: index out of range [7] with length 5
range
range
The output of the above snippet is as below -
以上代码段的输出如下-
length vs capacity
长度与容量
As mentioned before, we can provide capacity as an optional parameter while initializing the slice with make function. By default, it is the same as the length parameter. The capacity of the slice can be thought of as the amount of continuous storage that Go allocates to the slice. Once the length of the slice has reached its capacity, the Go environment would create a new backing array with double the capacity and copies all the elements in the existing array to the new. With the below example, let us see, how the capacity increases with the increase in the length —
如前所述,在使用make函数初始化切片时,我们可以提供容量作为可选参数。 默认情况下,它与length参数相同。 切片的容量可以认为是Go分配给切片的连续存储量。 一旦切片的长度达到其容量,Go环境将创建容量增加一倍的新后备阵列,并将现有阵列中的所有元素复制到新的阵列中。 在下面的示例中,让我们看一下容量如何随着长度的增加而增加-
Look how the capacity has doubled whenever the length reached a power of 2. When the length and the capacity of the slice are 4, an addition of a number has triggered the capacity to double.
看一下每当长度达到2的幂时,容量是如何增加一倍的。当切片的长度和容量为4时,数字的增加会触发容量增加一倍。
If we provide a custom capacity like — make([]int,6,6), capacity would follow the multiples of 6 like below —
如果我们提供自定义功能(例如-make([] int,6,6),则功能将遵循以下6的倍数—