室内设计网站平面案例,太原百度快速优化排名,宿松住房和城乡建设局网站,淮南移动网站建设引言
在Go中#xff0c;数组和切片是由有序的元素序列组成的数据结构。当需要处理许多相关值时#xff0c;这些数据集非常适合使用。它们使你能够将本应放在一起的数据放在一起#xff0c;压缩代码#xff0c;并一次性对多个值执行相同的方法和操作。
尽管Go中的数组和切…引言
在Go中数组和切片是由有序的元素序列组成的数据结构。当需要处理许多相关值时这些数据集非常适合使用。它们使你能够将本应放在一起的数据放在一起压缩代码并一次性对多个值执行相同的方法和操作。
尽管Go中的数组和切片都是有序的元素序列但两者之间存在显著差异。Go中的数组是一种数据结构由在创建时定义其容量的有序元素序列组成。一旦数组分配了大小就不能再改变它的大小。另一方面切片是数组的变长版本为使用这些数据结构的开发人员提供了更大的灵活性。切片构成了其他语言中的数组。
考虑到这些差异在某些特定情况下您将使用其中一个。如果您是Go的新手确定何时使用它们可能会令人困惑:尽管切片的多功能性使它们在大多数情况下是更合适的选择但在某些特定情况下数组可以优化程序的性能。
本文将详细介绍数组和切片为您在选择这些数据类型时做出适当的选择提供必要的信息。此外您还将回顾声明和使用数组和切片的最常见方法。本教程将首先描述数组以及如何操作它们然后解释切片及其区别。
数组
数组是包含一定数量元素的集合数据结构。因为数组的大小是静态的所以数据结构只需要分配一次内存而变长数据结构必须动态分配内存以便将来内存变得更大或更小。虽然数组的固定长度会让它们在使用时有些死板但一次性分配内存可以提高程序的速度和性能。因此开发人员在优化程序时如果数据结构永远不需要可变数量的元素通常会使用数组。
定义数组
数组是通过在方括号’[]中声明数组的大小和元素的数据类型来定义的。Go中的数组必须具有相同的[数据类型]在数据类型之后您可以在花括号{}中声明数组元素的单个值。
下面是声明数组的一般模式:
[capacity]data_type{element_values}**注意:**重要的是要记住每个新数组的声明都会创建一个不同的类型。因此尽管[2]int和[3]int都有整数元素但它们不同的长度使它们的数据类型不兼容。
如果不声明数组元素的值则默认值为0这意味着数组中的元素将为空。对于整数this用0表示对于字符串this用空字符串表示。
例如下面的数组numbers有三个还没有值的整数元素:
var numbers [3]int如果你打印numbers你会得到以下输出:
Output[0 0 0]如果想在创建数组时对元素的值进行赋值可以将值放在大括号中。一个设置了值的字符串数组如下所示:
[4]string{blue coral, staghorn coral, pillar coral, elkhorn coral}你可以将数组存储在变量中并将其打印出来:
coral : [4]string{blue coral, staghorn coral, pillar coral, elkhorn coral}
fmt.Println(coral)Output[blue coral staghorn coral pillar coral elkhorn coral]请注意在打印数组时没有对数组中的元素进行划分因此很难区分一个元素从哪里结束另一个元素从哪里开始。因此有时使用fmt.Printf函数是有帮助的它可以在将字符串打印到屏幕上之前格式化字符串。为动词%q提供这个命令指示函数在值周围加上引号:
fmt.Printf(%q\n, coral)Output[blue coral staghorn coral pillar coral elkhorn coral]现在每个项目都被引用了。\n动词指示格式化程序在末尾添加一行返回。
有了如何声明数组及其组成的一般概念你现在可以继续学习如何用索引号指定数组中的元素。
索引数组(和切片)
数组(以及切片)中的每个元素都可以通过索引来单独调用。每个元素对应一个索引数它是一个从索引数0开始的int值。
在下面的例子中我们将使用数组但你也可以使用切片因为它们的索引方式相同。
对于数组coral索引分解如下所示:
“blue coral”“staghorn coral”“pillar coral”“elkhorn coral”0123
第一个元素是字符串blue coral从索引0开始切片以索引3结束元素是elkhorn coral。
因为切片或数组中的每个元素都有对应的索引号所以我们能够以与其他顺序数据类型相同的方式访问和操作它们。
现在我们可以通过索引号来调用切片中的离散元素:
fmt.Println(coral[1])Outputstaghorn coral这个切片的索引号从0-3如前一个表所示。因此要单独调用任何元素我们将像这样引用索引编号:
coral[0] blue coral
coral[1] staghorn coral
coral[2] pillar coral
coral[3] elkhorn coral如果我们使用任何大于3的索引值来调用数组coral它将超出范围因为它将无效:
fmt.Println(coral[18])Outputpanic: runtime error: index out of range当索引数组或切片时必须始终使用正数。与某些语言允许您使用负数反向索引不同在Go中这样做将导致错误:
fmt.Println(coral[-1])Outputinvalid array index -1 (index must be non-negative)我们可以使用操作符连接数组中的字符串元素或与其他字符串切片:
fmt.Println(Sammy loves coral[0])OutputSammy loves blue coral我们可以将索引为0的字符串元素与字符串Sammy loves 连接起来。
通过索引号对应数组或切片中的元素我们能够离散地访问每个元素并使用这些元素。为了演示这一点我们接下来看看如何修改某个索引处的元素。
修改元素
我们可以通过将索引编号的元素设置为不同的值来使用索引来更改数组或切片中的元素。这使我们能够更好地控制切片和数组中的数据并允许我们以编程方式操作单个元素。
如果我们想要将数组coral中索引1处的元素的字符串值从staghorn coral改为foliose coral我们可以这样做:
coral[1] foliose coral现在当我们打印coral时数组将会不同:
fmt.Printf(%q\n, coral)Output[blue coral foliose coral pillar coral elkhorn coral]现在你已经知道了如何操作数组或切片中的单个元素下面来看两个函数它们能让你在处理集合数据类型时更加灵活。
使用len()计数元素
在Go中len()是一个内置函数用于帮助你处理数组和切片。与字符串一样你可以使用len()并将数组或切片作为参数传递来计算数组或切片的长度。
例如要找出coral数组中有多少个元素你可以使用:
len(coral)如果你打印数组 coral的长度会得到以下输出:
Output4这给出了数组4的int数据类型的长度这是正确的因为数组coral有四个元素:
coral : [4]string{blue coral, foliose coral, pillar coral, elkhorn coral}如果你创建一个包含更多元素的整数数组你也可以对其使用len()函数:
numbers : [13]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
fmt.Println(len(numbers))Output13尽管这些示例数组的项相对较少但在确定非常大的数组中有多少元素时len()函数特别有用。
接下来我们将介绍如何将元素添加到集合数据类型中并演示由于数组的长度是固定的添加这些静态数据类型将导致错误。
用append()添加元素
append()是Go中的一个内置方法它可以将元素添加到集合数据类型中。但是这个方法不适用于数组。如前所述数组与切片的主要区别在于数组的大小不能修改。这意味着虽然可以改变数组中元素的值但不能在定义数组后使其变大或变小。
让我们考虑一下你的coral数组:
coral : [4]string{blue coral, foliose coral, pillar coral, elkhorn coral}假设你想将元素black coral添加到这个数组中。如果你尝试对数组使用append()函数输入:
coral append(coral, black coral)Outputfirst argument to append must be slice; have [4]string为了解决这个问题让我们学习更多关于切片数据类型的内容如何定义切片以及如何将数组转换为切片。
切片
切片是Go中的一种数据类型它是一个可变的或可变的、有序的元素序列。由于切片的大小是可变的因此在使用它们时具有更大的灵活性;在处理将来可能需要扩展或收缩的数据集合时使用切片可以确保在试图操作集合的长度时不会出错。在大多数情况下这种可变性是值得的与数组相比切片有时需要重新分配内存。当你需要存储大量元素或迭代元素并希望能够随时修改这些元素时你可能会想使用slice数据类型。
定义切片
切片是通过声明数据类型来定义的数据类型之前是一组空的方括号([])以及大括号({})之间的元素列表。你会注意到与数组需要在括号中包含一个int来声明特定的长度不同切片在括号中没有任何东西来表示它的可变长度。
让我们创建一个包含string数据类型元素的切片:
seaCreatures : []string{shark, cuttlefish, squid, mantis shrimp, anemone}打印切片时我们可以看到切片中的元素:
fmt.Printf(%q\n, seaCreatures)Output[shark cuttlefish squid mantis shrimp anemone]如果你想创建一个特定长度的切片而不填充集合中的元素你可以使用内置的make()函数:
oceans : make([]string, 3)Output[ ]如果你想预分配一定容量的内存你可以向make()传入第三个参数:
oceans : make([]string, 3, 5)这将创建一个长度为3、预分配容量为5的零切片。
现在你知道如何声明切片了。然而这还不能解决我们之前在coral数组中遇到的错误。要对coral使用append()函数你首先需要学习如何对数组进行切片。
将数组切片
通过使用索引号来确定起点和终点可以调用数组中值的分段。这被称为切片数组你可以通过创建一个以冒号分隔的索引数字范围来做到这一点形式为[first_index:second_index]。然而重要的是要注意在对数组进行切片时结果是切片而不是数组。
假设你想只打印coral数组的中间元素不打印第一个和最后一个元素。你可以通过创建一个从索引1开始在索引3之前结束的切片来实现:
fmt.Println(coral[1:3])Output[foliose coral pillar coral]在创建切片时如[1:3]第一个数字是切片的起始位置(包括起始位置)第二个数字是第一个数字和你想要检索的元素总数的和:
array[starting_index : (starting_index length_of_slice)]在本例中调用第二个元素(或索引1)作为起点并总共调用了两个元素。计算如下:
array[1 : (1 2)]这就是你如何得到这个符号的:
coral[1:3]如果想将数组的开始或结束设置为切片的开始或结束点可以省略array[first_index:second_index]语法中的一个数字。例如如果你想打印数组coral的前三项——即blue coral、foliose coral和pillar coral——你可以输入:
fmt.Println(coral[:3])Output[blue coral foliose coral pillar coral]这打印了数组的开始部分在索引3之前停止。
要在数组末尾包含所有元素可以使用相反的语法:
fmt.Println(coral[1:])Output[foliose coral pillar coral elkhorn coral]本节讨论了如何通过切片调用数组的各个部分。接下来你将学习如何使用切片将整个数组转换为切片。
将数组转换为切片
如果你创建了一个数组并决定让它具有可变长度则可以将其转换为切片。要将数组转换为切片请使用本教程的slicing Arrays into Slices步骤中学习的切片过程只不过这次通过省略两个决定端点的索引号来选择整个切片:
coral[:]请记住你不能将变量coral转换为切片本身因为变量一旦在Go中定义其类型就不能更改。要解决这个问题可以将数组的整个内容以切片的形式复制到一个新变量中:
coralSlice : coral[:]如果你打印coralSlice你会收到以下输出:
Output[blue coral foliose coral pillar coral elkhorn coral]现在尝试像数组部分那样添加black coral元素对新转换后的切片使用append():
coralSlice append(coralSlice, black coral)
fmt.Printf(%q\n, coralSlice)这将输出添加了元素的切片:
Output[blue coral foliose coral pillar coral elkhorn coral black coral]我们也可以在一个append()语句中添加多个元素:
coralSlice append(coralSlice, antipathes, leptopsammia)Output[blue coral foliose coral pillar coral elkhorn coral black coral antipathes leptopsammia]要将两个切片组合在一起你可以使用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]现在你已经学习了如何将元素添加到切片中我们来看看如何删除一个元素。
从切片中删除元素
与其他语言不同Go不提供任何从切片中删除元素的内置函数。需要通过切片的方式将项目从切片中移除。
要删除一个元素必须切出该元素之前的元素切出该元素之后的元素然后将这两个新切片附加在一起而不包含要删除的元素。
如果i是待删除元素的索引则此过程的格式如下所示:
slice append(slice[:i], slice[i1:]...)从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]现在索引位置3处的元素即字符串elkhorn coral不再位于我们的切片coralSlice中。
我们也可以使用相同的方法删除范围。假设我们不仅要删除元素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)这段代码将从切片中取出索引3、4和5:
Output[blue coral foliose coral pillar coral leptopsammia massive coral soft coral]现在你已经知道了如何在切片中添加和删除元素让我们看看如何测量在任何给定时间切片可以容纳的数据量。
使用cap()测量切片的容量
由于切片的长度是可变的因此len()方法不是确定这种数据类型大小的最佳选择。相反你可以使用cap()函数来了解切片的容量。这将显示一个切片可以容纳多少个元素这是由该切片已经分配了多少内存决定的。
**注意:**因为数组的长度和容量总是相同的所以cap()函数对数组不起作用。
cap()的一个常见用途是使用预设的元素数量创建一个切片然后以编程方式填充这些元素。这避免了使用append()添加超出当前分配容量的元素时可能发生的潜在不必要的分配。
假设我们想创建一个数字列表0到3。我们可以在循环中使用append()来做到这一点或者我们可以先预分配切片然后使用cap()循环来填充值。
首先我们来看看如何使用append():
numbers : []int{}
for i : 0; i 4; i {numbers append(numbers, i)
}
fmt.Println(numbers)Output[0 1 2 3]在这个例子中我们创建了一个切片然后创建了一个for循环它将迭代四次。每次迭代都会将循环变量i的当前值添加到numbers切片的下标中。然而这可能会导致不必要的内存分配从而降低程序的速度。在给空切片添加容量时每次调用append时程序都会检查切片的容量。如果添加的元素使切片超过这个容量程序将分配额外的内存来计算它。这会给程序带来额外的开销并导致执行速度变慢。
现在让我们通过预先分配一定的长度/容量来在不使用append()的情况下填充切片:
numbers : make([]int, 4)
for i : 0; i cap(numbers); i {numbers[i] i
}fmt.Println(numbers)Output[0 1 2 3]在这个例子中我们使用make()来创建一个切片并让它预分配4个元素。然后我们在循环中使用cap()函数迭代每个置零的元素填充每个元素直到达到预分配的容量。在每个循环中我们将循环变量i的当前值放置到numbers切片的下标中。
虽然append()和cap()策略在功能上是等效的但cap()的例子避免了使用append()函数所需的任何额外内存分配。
构造多维切片
您还可以将由其他切片组成的切片定义为元素每个方括号中的列表都包含在父切片的大括号中。这样的切片集合称为多维切片。这些可以被认为是描绘多维坐标;例如一个由5个长为6个元素的切片组成的集合可以表示一个水平长度为5、垂直高度为6的二维网格。
让我们来看看下面的多维切片:
seaNames : [][]string{{shark, octopus, squid, mantis shrimp}, {Sammy, Jesse, Drew, Jamie}}为了访问切片中的元素我们需要使用多个索引每个维度对应一个索引:
fmt.Println(seaNames[1][0])
fmt.Println(seaNames[0][0])在上面的代码中我们首先标识索引1处切片的索引0处的元素然后标识索引0处切片的索引0处的元素。这将产生以下结果:
OutputSammy
shark下面是其余各个元素的索引值:
seaNames[0][0] shark
seaNames[0][1] octopus
seaNames[0][2] squid
seaNames[0][3] mantis shrimpseaNames[1][0] Sammy
seaNames[1][1] Jesse
seaNames[1][2] Drew
seaNames[1][3] Jamie在处理多维切片时一定要记住为了访问相关嵌套切片中的特定元素需要引用多个索引号。
总结
在本教程中您学习了在Go中使用数组和切片的基础知识。我们通过多个练习演示了数组的长度是固定的而切片的长度是可变的并发现了这种差异如何影响在不同情况下对这些数据结构的使用。