golang 数组和切片

介绍 (Introduction)

In Go, arrays and slices are data structures that consist of an ordered sequence of elements. These data collections are great to use when you want to work with many related values. They enable you to keep data together that belongs together, condense your code, and perform the same methods and operations on multiple values at once.

在Go中, 数组切片是由元素的有序序列组成的数据结构 。 当您要使用许多相关值时,这些数据收集非常有用。 它们使您可以将属于一起的数据保持在一起,压缩代码,并一次对多个值执行相同的方法和操作。

Although arrays and slices in Go are both ordered sequences of elements, there are significant differences between the two. An array in Go is a data structure that consists of an ordered sequence of elements that has its capacity defined at creation time. Once an array has allocated its size, the size can no longer be changed. A slice, on the other hand, is a variable length version of an array, providing more flexibility for developers using these data structures. Slices constitute what you would think of as arrays in other languages.

尽管Go中的数组和切片都是元素的有序序列,但是两者之间存在显着差异。 Go中的数组是一种数据结构 ,它由元素的有序序列组成,并在创建时定义了其容量。 数组分配大小后,就无法再更改大小。 另一方面, 切片是数组的可变长度版本,为使用这些数据结构的开发人员提供了更大的灵活性。 切片构成了其他语言中的数组。

Given these differences, there are specific situations when you would use one over the other. If you are new to Go, determining when to use them can be confusing: Although the versatility of slices make them a more appropriate choice in most situations, there are specific instances in which arrays can optimize the performance of your program.

鉴于这些差异,在某些情况下您会使用一种方法。 如果您不熟悉Go,那么确定何时使用它们可能会造成混淆:尽管slice的多功能性使其在大多数情况下成为更合适的选择,但在某些特定情况下,数组可以优化程序的性能。

This article will cover arrays and slices in detail, which will provide you with the necessary information to make the appropriate choice when choosing between these data types. Furthermore, you’ll review the most common ways to declare and work with both arrays and slices. The tutorial will first provide a description of arrays and how to manipulate them, followed by an explanation of slices and how they differ.

本文将详细介绍数组和切片,它们将为您提供必要的信息,以便在这些数据类型之间进行选择时做出适当的选择。 此外,您将回顾声明和使用数组和切片的最常用方法。 本教程将首先描述数组以及如何操作它们,然后解释切片以及它们之间的区别。

数组 (Arrays)

Arrays are collection data structures with a set number of elements. Because the size of an array is static, the data structure only needs to allocate memory once, as opposed to a variable length data structure that must dynamically allocate memory so that it can become larger or smaller in the future. Although the fixed length of arrays can make them somewhat rigid to work with, the one-time memory allocation can increase the speed and performance of your program. Because of this, developers typically use arrays when optimizing programs in instances where the data structure will never need a variable amount of elements.

数组是具有一定数量元素的集合数据结构。 由于数组的大小是静态的,因此数据结构只需要分配一次内存,而可变长度数据结构则必须动态分配内存,以便将来可以变大或变小。 尽管固定长度的数组使它们在使用时有些僵化,但是一次性内存分配可以提高程序的速度和性能。 因此,开发人员通常在数据结构永远不需要可变数量的元素的实例中优化程序时使用数组。

定义数组 (Defining an Array)

Arrays are defined by declaring the size of the array in brackets [ ], followed by the data type of the elements. An array in Go must have all its elements be the same data type. After the data type, you can declare the individual values of the array elements in curly brackets { }.

通过在方括号[ ]声明数组的大小,然后声明元素的数据类型来定义数组。 Go中的数组必须使其所有元素都具有相同的数据类型 。 在数据类型之后,可以在大括号{ }声明数组元素的各个值。

The following is the general schema for declaring an array:

以下是声明数组的一般模式:

[capacity]data_type{element_values}

Note: It is important to remember that every declaration of a new array creates a distinct type. So, although [2]int and [3]int both have integer elements, their differing lengths make their data types incompatible.

注意:请务必记住,新数组的每个声明都会创建一个不同的类型。 因此,尽管[2]int[3]int都具有整数元素,但是它们不同的长度使它们的数据类型不兼容。

If you do not declare the values of the array’s elements, the default is zero-valued, which means that the elements of the array will be empty. For integers, this is represented by 0, and for strings this is represented by an empty string.

如果不声明数组元素的值,则默认值为零值,这意味着数组元素将为空。 对于整数,它由0表示,对于字符串,则由空字符串表示。

For example, the following array numbers has three integer elements that do not yet have a value:

例如,以下数组numbers具有三个没有值的整数元素:

var numbers [3]int

If you printed numbers, you would receive the following output:

如果您打印numbers ,您将收到以下输出:


   
Output
[0 0 0]

If you would like to assign the values of the elements when you create the array, place the values in curly brackets. An array of strings with set values looks like this:

如果要在创建数组时分配元素的值,请将其值放在大括号中。 具有设置值的字符串数组如下所示:

[4]string{"blue coral", "staghorn coral", "pillar coral", "elkhorn coral"}

You can store an array in a variable and print it out:

您可以将数组存储在变量中并打印出来:

coral := [4]string{"blue coral", "staghorn coral", "pillar coral", "elkhorn coral"}
fmt.Println(coral)

Running a program with the preceding lines would give you the following output:

使用前几行运行程序将为您提供以下输出:


   
Output
[blue coral staghorn coral pillar coral elkhorn coral]

Notice that there is no delineation between the elements in the array when it is printed, making it difficult to tell where one element ends and another begins. Because of this, it is sometimes helpful to use the fmt.Printf function instead, which can format strings before printing them to the screen. Provide the %q verb with this command to instruct the function to put quotation marks around the values:

请注意,打印时数组中的元素之间没有描述,因此很难判断一个元素在哪里结束而另一个在哪里开始。 因此,有时改用fmt.Printf函数会有所帮助,该函数可以在将字符串打印到屏幕之前对其进行格式化。 为此命令提供%q动词,以指示函数在值周围加上引号:

fmt.Printf("%q\n", coral)

This will result in the following:

这将导致以下结果:


   
Output
["blue coral" "staghorn coral" "pillar coral" "elkhorn coral"]

Now each item is quoted. The \n verb instructs to the formatter to add a line return at the end.

现在,每个项目都被引用。 动词\n指示格式化程序在末尾添加换行符。

With a general idea of how to declare arrays and what they consist of, you can now move on to learning how to specify elements in an array with an index number.

了解了如何声明数组及其组成的一般概念,现在您可以继续学习如何在数组中使用索引号指定元素。

索引数组(和切片) (Indexing Arrays (and Slices))

Each element in an array (and also a slice) can be called individually through indexing. Each element corresponds to an index number, which is an int value starting from the index number 0 and counting up.

数组中的每个元素(以及切片)都可以通过索引进行单独调用。 每个元素对应一个索引号,它是一个从索引号0并向上计数的int值。

We will use an array in the following examples, but you could use a slice as well, since they are identical in how you index both of them.

在下面的示例中,我们将使用数组,但是您也可以使用切片,因为它们在索引它们的方式上是相同的。

For the array coral, the index breakdown looks like this:

对于array coral ,索引分解如下所示:

“blue coral”“staghorn coral”“pillar coral”“elkhorn coral”
0123
“蓝珊瑚” “鹿角珊瑚” “柱状珊瑚” “麋角珊瑚”
0 1个 2 3

The first element, the string "blue coral", starts at index 0, and the slice ends at index 3 with the element "elkhorn coral".

第一个元素是字符串"elkhorn coral" "blue coral" ,从索引0开始,而切片在索引3 "elkhorn coral"元素"elkhorn coral"

Because each element in a slice or array has a corresponding index number, we’re able to access and manipulate them in the same ways we can with other sequential data types.

因为切片或数组中的每个元素都有一个对应的索引号,所以我们能够以与其他顺序数据类型相同的方式来访问和操作它们。

Now we can call a discrete element of the slice by referring to its index number:

现在,我们可以通过引用切片的索引号来调用切片的离散元素:

fmt.Println(coral[1])

   
Output
staghorn coral

The index numbers for this slice range from 0-3, as shown in the previous table. So to call any of the elements individually, we would refer to the index numbers like this:

如上表所示,此切片的索引号范围是0-3 。 因此,要单独调用任何元素,我们将引用这样的索引号:

coral[0] = "blue coral"
coral[1] = "staghorn coral"
coral[2] = "pillar coral"
coral[3] = "elkhorn coral"

If we call the array coral with an index number of any that is greater than 3, it will be out of range as it will not be valid:

如果我们用索引号大于3的任何一个来调用数组coral ,则它将超出范围,因为它将无效:

fmt.Println(coral[18])

   
Output
panic: runtime error: index out of range

When indexing an array or slice, you must always use a positive number. Unlike some languages that let you index backwards with a negative number, doing that in Go will result in an error:

为数组或切片建立索引时,必须始终使用正数。 与某些允许您使用负数向后索引的语言不同,在Go中执行此操作将导致错误:

fmt.Println(coral[-1])

   
Output
invalid array index -1 (index must be non-negative)

We can concatenate string elements in an array or slice with other strings using the + operator:

我们可以使用+运算符将数组或切片中的字符串元素与其他字符串连接起来:

fmt.Println("Sammy loves " + coral[0])

   
Output
Sammy loves blue coral

We were able to concatenate the string element at index number 0 with the string "Sammy loves ".

我们能够将索引号为0的字符串元素与字符串"Sammy loves "

With index numbers that correspond to elements within an array or a slice, we’re able to access each element discretely and work with those elements. To demonstrate this, we will next look at how to modify an element at a certain index.

使用与数组或切片中的元素相对应的索引号,我们可以离散地访问每个元素并使用这些元素。 为了证明这一点,我们接下来将研究如何在特定索引处修改元素。

修改元素 (Modifying Elements)

We can use indexing to change elements within an array or slice by setting an index numbered element equal to a different value. This gives us greater control over the data in our slices and arrays, and will allow us to programmatically manipulate individual elements.

通过将索引编号的元素设置为等于不同的值,我们可以使用索引来更改数组或切片中的元素。 这使我们可以更好地控制切片和数组中的数据,并允许我们以编程方式操作单个元素。

If we want to change the string value of the element at index 1 of the array coral from "staghorn coral" to "foliose coral", we can do so like this:

如果我们想将数组coral索引1的元素的字符串值从"foliose coral" "staghorn coral"更改为"foliose coral" ,我们可以这样做:

coral[1] = "foliose coral"

Now when we print coral, the array will be different:

现在,当我们打印coral ,数组将有所不同:

fmt.Printf("%q\n", coral)

   
Output
["blue coral" "foliose coral" "pillar coral" "elkhorn coral"]

Now that you know how to manipulate individual elements of an array or a slice, let’s look at a couple of functions that will give you more flexibility when working with collection data types.

既然您知道如何操作数组或切片的各个元素,那么让我们看一下几个函数,这些函数在处理集合数据类型时将为您提供更大的灵活性。

len()计数元素 (Counting Elements with len())

In Go, len() is a built-in function made to help you work with arrays and slices. Like with strings, you can calculate the length of an array or slice by using len() and passing in the array or slice as a parameter.

在Go中, len()是一个内置函数,旨在帮助您处理数组和切片。 与字符串一样,您可以使用len()并将数组或切片作为参数传递来计算数组或切片的长度。

For example, to find how many elements are in the coral array, you would use:

例如,要查找coral阵列中有多少个元素,可以使用:

len(coral)

If you print out the length for the array coral, you’ll receive the following output:

如果打印出来的长度为阵coral ,您会收到以下输出:


   
Output
4

This gives the length of the array 4 in the int data type, which is correct because the array coral has four items:

这给出了int数据类型中数组4的长度,这是正确的,因为数组coral具有四个项目:

coral := [4]string{"blue coral", "foliose coral", "pillar coral", "elkhorn coral"}

If you create an array of integers with more elements, you could use the len() function on this as well:

如果创建具有更多元素的整数数组,则也可以在该数组上使用len()函数:

numbers := [13]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
fmt.Println(len(numbers))

This would result in the following output:

这将导致以下输出:


   
Output
13

Although these example arrays have relatively few items, the len() function is especially useful when determining how many elements are in very large arrays.

尽管这些示例数组的项相对较少,但是len()函数在确定非常大的数组中有多少个元素时特别有用。

Next, we will cover how to add an element to a collection data type, and demonstrate how, because of the fixed length of arrays, appending these static data types will result in an error.

接下来,我们将介绍如何将元素添加到集合数据类型,并演示由于数组的固定长度,如何添加这些静态数据类型将导致错误。

append()追加元素 (Appending Elements with append())

append() is a built-in method in Go that adds elements to a collection data type. However, this method will not work when used with an array. As mentioned before, the primary way in which arrays are different from slices is that the size of an array cannot be modified. This means that while you can change the values of elements in an array, you can’t make the array larger or smaller after it has been defined.

append()是Go中的内置方法,可将元素添加到集合数据类型。 但是,与数组一起使用时,此方法将不起作用。 如前所述,数组与切片不同的主要方法是无法修改数组的大小。 这意味着,虽然可以更改数组中元素的值,但是在定义数组后不能再放大或缩小。

Let’s consider your coral array:

让我们考虑一下您的coral阵列:

coral := [4]string{"blue coral", "foliose coral", "pillar coral", "elkhorn coral"}

Say you want to add the item "black coral" to this array. If you try to use the append() function with the array by typing:

假设您要将"black coral"项添加到此数组中。 如果尝试通过键入以下命令对数组使用append()函数:

coral = append(coral, "black coral")

You will receive an error as your output:

您的输出将收到一个错误:


   
Output
first argument to append must be slice; have [4]string

To fix this, let’s learn more about the slice data type, how to define a slice, and how to convert from an array to a slice.

要解决此问题,让我们了解更多有关slice数据类型,如何定义slice以及如何从数组转换为slice的信息。

切片 (Slices)

A slice is a data type in Go that is a mutable, or changeable, ordered sequence of elements. Since the size of a slice is variable, there is a lot more flexibility when using them; when working with data collections that may need to expand or contract in the future, using a slice will ensure that your code does not run into errors when trying to manipulate the length of the collection. In most cases, this mutability is worth the possible memory re-allocation sometimes required by slices when compared to arrays. When you need to store a lot of elements or iterate over elements and you want to be able to readily modify those elements, you’ll likely want to work with the slice data type.

切片是Go中的一种数据类型,它是可变的或可变的有序元素序列。 由于切片的大小是可变的,因此使用它们时具有更大的灵活性。 当使用将来可能需要扩展或收缩的数据收集时,使用分片将确保在尝试操纵收集长度时代码不会出错。 在大多数情况下,与数组相比,这种可变性值得切片有时需要进行可能的内存重新分配。 当您需要存储很多元素或遍历元素并且希望能够轻松修改这些元素时,您可能需要使用slice数据类型。

定义切片 (Defining a Slice)

Slices are defined by declaring the data type preceded by an empty set of square brackets ([]) and a list of elements between curly brackets ({}). You’ll notice that, as opposed to arrays that require an int in between the brackets to declare a specific length, a slice has nothing between the brackets, representing its variable length.

通过声明数据类型,然后声明一组空的方括号( [] )和大括号之间的元素列表( {} ),来定义切片。 您会注意到,与需要在方括号之间声明一个特定长度的int数组相反,切片在方括号之间没有任何内容来表示其可变长度。

Let’s create a slice that contains elements of the string data type:

让我们创建一个包含字符串数据类型元素的切片:

seaCreatures := []string{"shark", "cuttlefish", "squid", "mantis shrimp", "anemone"}

When we print out the slice, we can see the elements that are in the slice:

当我们打印出切片时,我们可以看到切片中的元素:

fmt.Printf("%q\n", seaCreatures)

This will result in the following:

这将导致以下结果:


   
Output
["shark" "cuttlefish" "squid" "mantis shrimp" "anemone"]

If you would like to create a slice of a certain length without populating the elements of the collection yet, you can use the built-in make() function:

如果要创建一定长度的切片而不填充集合的元素,可以使用内置的make()函数:

oceans := make([]string, 3)

If you printed this slice, you would get:

如果您打印此切片,您将得到:


   
Output
["" "" ""]

If you want to pre-allocate the memory for a certain capacity, you can pass in a third argument to make():

如果要为某个容量预分配内存,则可以将第三个参数传递给make()

oceans := make([]string, 3, 5)

This would make a zeroed slice with a length of 3 and a pre-allocated capacity of 5 elements.

这将形成一个长度为3且预分配容量为5元素的置零切片。

You now know how to declare a slice. However, this does not yet solve the error we had with the coral array earlier. To use the append() function with coral, you will first have to learn how to slice out sections of an array.

您现在知道了如何声明切片。 但是,这还不能解决我们先前对coral阵列的错误。 要对coral使用append()函数,您首先必须学习如何分割数组的各个部分。

将阵列切成片 (Slicing Arrays into Slices)

By using index numbers to determine beginning and endpoints, you can call a subsection of the values within an array. This is called slicing the array, and you can do this by creating a range of index numbers separated by a colon, in the form of [first_index:second_index]. It is important to note however, that when slicing an array, the result is a slice, not an array.

通过使用索引号确定起点和终点,可以在数组中调用值的子部分。 这称为切片数组,您可以通过以[ first_index : second_index ]的形式创建一系列由冒号分隔的索引号来实现。 但是,重要的是要注意,对数组进行切片时,结果是切片,而不是数组。

Let’s say you would like to just print the middle items of the coral array, without the first and last element. You can do this by creating a slice starting at index 1 and ending just before index 3:

假设您只想打印出coral数组的中间项目,而没有第一个和最后一个元素。 您可以通过创建从索引1开始到索引3之前结束的切片来实现此目的:

fmt.Println(coral[1:3])

Running a program with this line would yield the following:

使用此行运行程序将产生以下结果:


   
Output
[foliose coral pillar coral]

When creating a slice, as in [1:3], the first number is where the slice starts (inclusive), and the second number is the sum of the first number and the total number of elements you would like to retrieve:

在创建切片时,如[1:3] ,第一个数字是切片开始的位置(包含),第二个数字是第一个数字与要检索的元素总数的和:

array[starting_index : (starting_index + length_of_slice)]

In this instance, you called the second element (or index 1) as the starting point, and called two elements in total. This is how the calculation would look:

在这种情况下,您将第二个元素(或索引1)称为起点,并且总共调用了两个元素。 计算结果如下:

array[1 : (1 + 2)]

Which is how you arrived at this notation:

您是如何得出此表示法的:

coral[1:3]

If you want to set the beginning or end of the array as a starting or end point of the slice, you can omit one of the numbers in the array[first_index:second_index] syntax. For example, if you want to print the first three items of the array coral — which would be "blue coral", "foliose coral", and "pillar coral" — you can do so by typing:

如果要将数组的起点或终点设置为切片的起点或终点,则可以省略array[ first_index : second_index ]语法中的数字之一。 例如,如果您要打印阵列coral的前三项(即"blue coral""foliose coral""pillar coral" ),可以通过键入以下内容进行打印:

fmt.Println(coral[:3])

This will print:

这将打印:


   
Output
[blue coral foliose coral pillar coral]

This printed the beginning of the array, stopping right before index 3.

这打印了数组的开始,在索引3之前停止。

To include all the items at the end of an array, you would reverse the syntax:

要在数组末尾包含所有项目,您可以颠倒语法:

fmt.Println(coral[1:])

This would give the following slice:

这将给出以下内容:


   
Output
[foliose coral pillar coral elkhorn coral]

This section discussed calling individual parts of an array by slicing out subsections. Next, you’ll learn how to use slicing to convert entire arrays into slices.

本节讨论了通过切出小节来调用数组的各个部分。 接下来,您将学习如何使用切片将整个数组转换为切片。

从数组转换为切片 (Converting from an Array to a Slice)

If you create an array and decide that you need it to have a variable length, you can convert it to a slice. To convert an array to a slice, use the slicing process you learned in the Slicing Arrays into Slices step of this tutorial, except this time select the entire slice by omitting both of the index numbers that would determine the endpoints:

如果创建数组并确定需要使其具有可变长度,则可以将其转换为切片。 要将数组转换为切片,请使用在本教程的“将数组切片成切片”步骤中学习的切片过程,除了这次通过省略两个将确定端点的索引号来选择整个切片:

coral[:]

Keep in mind that you can’t convert the variable coral to a slice itself, since once a variable is defined in Go, its type can’t be changed. To work around this, you can copy the entire contents of the array into a new variable as a slice:

请记住,您无法将可变的coral转换为切片本身,因为一旦在Go中定义了变量,就无法更改其类型。 要解决此问题,您可以将数组的全部内容复制为一个新的变量作为切片:

coralSlice := coral[:]

If you printed coralSlice, you would receive the following output:

如果您打印coralSlice ,您将收到以下输出:


   
Output
[blue coral foliose coral pillar coral elkhorn coral]

Now, try to add the black coral element like in the array section, using append() with the newly converted slice:

现在,尝试使用array append()和新转换后的slice一样,在array部分中添加black coral元素:

coralSlice = append(coralSlice, "black coral")
fmt.Printf("%q\n", coralSlice)

This will output the slice with the added element:

这将输出带有添加的元素的切片:


   
Output
["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral"]

We can also add more than one element in a single append() statement:

我们还可以在一个append()语句中添加多个元素:

coralSlice = append(coralSlice, "antipathes", "leptopsammia")

   
Output
["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia"]

To combine two slices together, you can use append(), but you must expand the second argument to append using the ... expansion syntax:

要将两个切片组合在一起,可以使用append() ,但是必须使用...扩展语法将第二个参数扩展为append:

moreCoral := []string{"massive coral", "soft coral"}
coralSlice = append(coralSlice, moreCoral...)

   
Output
["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]

Now that you have learned how to append an element to your slice, we will take a look at how to remove one.

既然您已经了解了如何将元素添加到切片,那么我们将看一下如何删除元素。

从切片中删除元素 (Removing an Element from a Slice)

Unlike other languages, Go does not provide any built-in functions to remove an element from a slice. Items need to be removed from a slice by slicing them out.

与其他语言不同,Go不提供任何内置功能来从切片中删除元素。 需要通过切片将它们从切片中移除。

To remove an element, you must slice out the items before that element, slice out the items after that element, then append these two new slices together without the element that you wanted to remove.

要删除元素,必须先切出该元素之前的项目,再切出该元素之后的项目,然后将这两个新的切面附加在一起而没有要删除的元素。

If i is the index of the element to be removed, then the format of this process would look like the following:

如果i是要删除的元素的索引,则此过程的格式如下所示:

slice = append(slice[:i], slice[i+1:]...)

From coralSlice, let’s remove the item "elkhorn coral". This item is located at the index position of 3.

coralSlice ,我们删除"elkhorn coral" 。 此项位于索引位置3

coralSlice := []string{"blue coral", "foliose coral", "pillar coral", "elkhorn coral", "black coral", "antipathes", "leptopsammia", "massive coral", "soft coral"}

coralSlice = append(coralSlice[:3], coralSlice[4:]...)

fmt.Printf("%q\n", coralSlice)

   
Output
["blue coral" "foliose coral" "pillar coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]

Now the element at index position 3, the string "elkhorn coral", is no longer in our slice coralSlice.

现在,在指数位置的元素3 ,字符串"elkhorn coral" ,是在我们的片不再coralSlice

We can also delete a range with the same approach. Say we wanted to remove not only the item "elkhorn coral", but "black coral" and "antipathes" as well. We can use a range in the expression to accomplish this:

我们也可以使用相同的方法删除范围。 假设我们不仅要删除"elkhorn coral" ,还要删除"black coral""antipathes" 。 我们可以在表达式中使用范围来完成此任务:

coralSlice := []string{"blue coral", "foliose coral", "pillar coral", "elkhorn coral", "black coral", "antipathes", "leptopsammia", "massive coral", "soft coral"}

coralSlice = append(coralSlice[:3], coralSlice[6:]...)

fmt.Printf("%q\n", coralSlice)

This code will take out index 3, 4, and 5 from the slice:

此代码将取出索引34 ,和5从切片:


   
Output
["blue coral" "foliose coral" "pillar coral" "leptopsammia" "massive coral" "soft coral"]

Now that you know how to add and remove elements from a slice, let’s look at how to measure the amount of data a slice can hold at any given time.

现在您知道了如何在切片中添加和删除元素,让我们看一下如何测量切片在任何给定时间可以保存的数据量。

使用cap()测量切片的容量 (Measuring the Capacity of a Slice with cap())

Since slices have a variable length, the len()method is not the best option to determine the size of this data type. Instead, you can use the cap() function to learn the capacity of a slice. This will show you how many elements a slice can hold, which is determined by how much memory has already been allocated for the slice.

由于切片的长度是可变的,因此len()方法不是确定此数据类型大小的最佳选择。 相反,您可以使用cap()函数来学习切片的容量。 这将显示一个切片可以容纳多少个元素,这取决于为该切片分配了多少内存。

Note: Because the length and capacity of an array are always the same, the cap() function will not work on arrays.

注意:由于数组的长度和容量始终相同,因此cap()函数不适用于数组。

A common use for cap() is to create a slice with a preset number of elements and then fill in those elements programmatically. This avoids potential unnecessary allocations that could occur by using append() to add elements beyond the capacity currently allocated for.

cap()常见用法是使用预定数量的元素创建一个切片,然后以编程方式填充这些元素。 这避免了使用append()添加超出当前分配容量的元素时可能发生的潜在不必要分配。

Let’s take the scenario where we want to make a list of numbers, 0 through 3. We can use append() in a loop to do so, or we can pre-allocate the slice first and use cap() to loop through to fill the values.

让我们假设要列出一个数字列表,从03 。 我们可以在循环中使用append()来执行此操作,也可以先预先分配切片,然后使用cap()进行循环以填充值。

First, we can look at using append():

首先,我们可以看看使用append()

numbers := []int{}
for i := 0; i < 4; i++ {
    numbers = append(numbers, i)
}
fmt.Println(numbers)

   
Output
[0 1 2 3]

In this example, we created a slice, and then created a for loop that would iterate four times. Each iteration appended the current value of the loop variable i into the index of the numbers slice. However, this could lead to unnecessary memory allocations that could slow down your program. When adding to an empty slice, each time you make a call to append, the program checks the capacity of the slice. If the added element makes the slice exceed this capacity, the program will allocate additional memory to account for it. This creates additional overhead in your program and can result in a slower execution.

在此示例中,我们创建了一个分片,然后创建了一个将循环进行四次的for循环。 每次迭代都将循环变量i的当前值附加到numbers切片的索引中。 但是,这可能导致不必要的内存分配,从而降低程序速度。 当添加到空片时,每次调用追加时,程序都会检查片的容量。 如果添加的元素使分片超出此容量,则程序将分配额外的内存以解决该问题。 这会在程序中产生额外的开销,并可能导致执行速度变慢。

Now let’s populate the slice without using append() by pre-allocating a certain length/capacity:

现在让我们通过预先分配一定的长度/容量来填充切片而不使用append()

numbers := make([]int, 4)
for i := 0; i < cap(numbers); i++ {
    numbers[i] = i
}

fmt.Println(numbers)

   
Output
[0 1 2 3]

In this example, we used make() to create a slice and had it pre-allocate 4 elements. We then used the cap() function in the loop to iterate through each zeroed element, filling each until it reached the pre-allocated capacity. In each loop, we placed the current value of the loop variable i into the index of the numbers slice.

在此示例中,我们使用make()创建一个slice并使其预先分配了4元素。 然后,我们在循环中使用cap()函数遍历每个清零的元素,填充每个元素直到其达到预先分配的容量。 在每个循环中,我们将循环变量i的当前值放入numbers切片的索引中。

While the append() and the cap() strategies are both functionally equivalent, the cap() example avoids any additional memory allocations that would have been needed using the append() function.

尽管append()cap()策略在功能上都是等效的,但是cap()示例避免了使用append()函数本来需要的任何其他内存分配。

构造多维切片 (Constructing Multidimensional Slices)

You can also define slices that consist of other slices as elements, with each bracketed list enclosed inside the larger brackets of the parent slice. Collections of slices like these are called multidimensional slices. These can be thought of as depicting multidimensional coordinates; for example, a collection of five slices that are each six elements long could represent a two-dimensional grid with a horizontal length of five and a vertical height of six.

您还可以将由其他切片组成的切片定义为元素,每个方括号列表都包含在父切片的大括号内。 这些切片的集合称为多维切片 。 可以将它们视为描绘多维坐标; 例如,五个切片的集合(每个切片有六个元素长)可以表示一个二维网格,其水平长度为5,垂直高度为6。

Let’s examine the following multidimensional slice:

让我们检查以下多维切片:

seaNames := [][]string{{"shark", "octopus", "squid", "mantis shrimp"}, {"Sammy", "Jesse", "Drew", "Jamie"}}

To access an element within this slice, we will have to use multiple indices, one for each dimension of the construct:

要访问此片中的元素,我们将必须使用多个索引,每个索引用于构造的每个维度:

fmt.Println(seaNames[1][0])
fmt.Println(seaNames[0][0])

In the preceding code, we first identify the element at index 0 of the slice at index 1, then we indicate the element at index 0 of the slice at index 0. This will yield the following:

在前面的代码中,我们首先在索引1的切片的索引0处标识元素,然后在索引0的切片的索引0处标识元素。 这将产生以下结果:


   
Output
Sammy shark

The following are the index values for the rest of the individual elements:

以下是其余各个元素的索引值:

seaNames[0][0] = "shark"
seaNames[0][1] = "octopus"
seaNames[0][2] = "squid"
seaNames[0][3] = "mantis shrimp"

seaNames[1][0] = "Sammy"
seaNames[1][1] = "Jesse"
seaNames[1][2] = "Drew"
seaNames[1][3] = "Jamie"

When working with multidimensional slices, it is important to keep in mind that you’ll need to refer to more than one index number in order to access specific elements within the relevant nested slice.

使用多维切片时,请务必记住,您需要引用多个索引号才能访问相关嵌套切片中的特定元素。

结论 (Conclusion)

In this tutorial, you learned the foundations of working with arrays and slices in Go. You went through multiple exercises to demonstrate how arrays are fixed in length, whereas slices are variable in length, and discovered how this difference affects the situational uses of these data structures.

在本教程中,您学习了在Go中使用数组和切片的基础。 您进行了多次练习,以演示数组的长度固定,而切片的长度可变,并发现这种差异如何影响这些数据结构的情境使用。

To continue studying data structures in Go, check out our article on Understanding Maps in Go, or explore the entire How To Code in Go series.

要继续研究Go中的数据结构,请查看关于理解Go中的地图的文章,或探索整个如何在Go中编写代码系列。

翻译自: https://www.digitalocean.com/community/tutorials/understanding-arrays-and-slices-in-go

golang 数组和切片

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐