golang 切片和数组_go中的切片和数组的初学者指南

golang 切片和数组

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 —

几乎所有主流语言都有数组。 数组是某种类型的索引列表。 数组有固定的大小,我们在初始化时提供。 数组中元素的索引从零开始。 在下面的两个之一中初始化了一个字符串数组-

To access and assign an element, it can be done like this — arr[index]. As indexing starts at 0, the max possible index is the length of array-1. What if we try to access an element with an index greater than the length of the array?something like — array[4]. It would result in the error as follows —

要访问和分配元素,可以这样完成— arr [index]。 随着索引从0开始,最大可能索引为length of array-1length of array-1 。 如果我们尝试访问索引大于数组长度的元素该怎么办?类似— array[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 —

切片是数组的一部分。 切片包含对基础数组的引用。 它们是可调整大小的,即。 一个可以追加元素或删除现有元素。 切片不保存数据,它们仅保存指向元素数组的指针。 切片如下创建—

As in the above example, slices are created from the underlying array in this format — array[startIndex : endIndex] . One caveat here is that startIndex is inclusive and endIndex is exclusive. That is why the output of the above snippet is [“World”, “!”] .

如上例所示,从基础数组以以下格式创建切片array[startIndex : endIndex] 。 需要注意的是, startIndex是包含在内的,而endIndex是排斥的。 因此,以上代码段的输出为[“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

Note: length of a slice is calculated from the built-in function len() and capacity through cap() .

注意:切片的长度由内置函数len()和容量通过cap()计算得出。

Slices can be created without an underlying array as well, although internally, Go holds the data in the array. We can use the Go’s builtin make() function —

切片也可以在没有底层数组的情况下创建,尽管在内部,Go将数据保存在数组中。 我们可以使用Go的内置make()函数-

make([]int, 5) 

creates a slice of type int and length: 5. As the zero value of int type is 0, the above slice looks like [0 0 0 0 0] when printed.

创建一个类型为int和length的切片:5.由于int类型的零值为0,因此在打印时上述切片看起来像[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]

Initially, a slice is cut from the array with startIndex as 2 and ending at 4. When we append 9 to the slice, it has become [3 4 5 9] . An interesting observation here is how the fifth index of the array is updated to 9 from 6. This is because as discussed above, slices hold the pointer to the array. Any addition would take effect to the array it backs. A curious thought here, the length of the elements in the array is five and the last element in the slice now points to the last element in the array. What happens when we try to append an element to the slice?

最初,以startIndex为2并从4结束的数组中切出一个切片。将9附加到切片后,它变为[3 4 5 9] 。 这里有趣的观察是如何将数组的第五个索引从6更新为9。这是因为如上所述,切片将指针指向数组。 任何添加都会对其后退的阵列生效。 奇怪的是,数组中元素的长度为5,而切片中的最后一个元素现在指向数组中的最后一个元素。 当我们尝试向切片添加元素时会发生什么?

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

As expected, the capacity has doubled from 4 to 8. Now any update to the slice would not have an effect on the oldarray it used to point before.

正如预期的那样,容量从4倍增加到8倍。现在,对切片的任何更新都不会影响它以前指向的旧array

make()

使()

Through the make() function, we can create a slice without having to explicitly initialize an array and cutting a slice from it. What make() does is that it creates an internal array with the length and the optional capacity parameters. This internal array created in the background and is not visible to programmers. Let us take an example —

通过make()函数,我们可以创建切片,而不必显式初始化数组并从中剪切切片。 make()作用是使用length和可选的capacity参数创建一个内部数组。 此内部数组在后台创建,并且对程序员不可见。 让我们举一个例子

By using append(), we can make the list grow in size. And as before, a specific element can be accessed in the usual manner — 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

迭代

Slices can be manipulated and access via iterating over them with loops. Let us understand how it can be done with for loops in the example below —

可通过循环遍历切片来操作和访问切片。 让我们了解如何在下面的示例中使用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

Iterating over a slice can be performed using the 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的倍数—

That’s it, this basic understanding about the internals of slices gives a good start for playing around with Go. Try this https://play.golang.org/ for writing little snippets of Go.

就是这样,对slice内部的基本了解为使用Go打下了良好的开端。 尝试使用此https://play.golang.org/编写Go的小片段。

Refer to this official blog https://blog.golang.org/slices for an even better understanding of the concepts and features around slices.

请参阅此官方博客https://blog.golang.org/slices ,以更好地了解切片的概念和功能。

翻译自: https://levelup.gitconnected.com/a-beginners-guide-to-slices-and-arrays-in-go-67ed9e54e133

golang 切片和数组

你可能感兴趣的:(golang)