Golang中的数组和切片指南

 go教练   2019-07-01 14:24   53 人阅读  0 条评论

首先,很容易看到数组和切片好像是同一个东西:表示列表的数据结构。然而,它们实际上彼此完全不同,今下面我们就一起来看看吧。

 微信截图_20190701092923.png

数组

数组是固定的数据列表。这里的重点是固定的,因为一旦设置了数组的长度,它就无法更改。

我们举一个声明了四个整数的数组的例子:

arr := [4]int{3, 2, 5, 4} 复制代码 长度和类型

我们在上面的例子中定义的arr变量的类型是[4] int,它是一个大小为 4 的数组。这里需要注意的是,4包含在类型定义中。

这意味着两个不同长度的数组实际上是 两个不同的类型。所以不能将不同长度的数组视为一种类型,也不能将其中一个的值分配给另一个:

longerArr := [5]int{5, 7, 1, 2, 0} longerArr = arr // 会抛出编译错误 longerArr == arr // 会抛出编译错误 复制代码

我发现考虑数组的一个好方法就是结构体。如果我们可以构造数组等价的结构体,它可能看起来像这样:

// 长度为 4 的数组的等价结构体 type int4 struct { e0 int e1 int e2 int e3 int } // 长度为 5 的数组的等价结构体 type int5 struct { e0 int e1 int e2 int e3 int e5 int } arr := int4{3, 2, 5, 4} longerArr := int5{5, 7, 1, 2, 0} 复制代码

不建议执行此操作,但这是一个很好的方法来了解为何不同长度的数组是完全不同的类型。

内存表示

数组存储为指定类型的n块的序列:

 微信截图_20190701092944.png

初始化数组类型的变量后,将立即分配此内存。

引用传递

Go 中,没有引用传递。一切都是通过值传递的。如果将数组的值分配给另一个变量,则会复制整个值。

 微信截图_20190701092958.png

如果只想将“引用”传递给数组,可以使用指针:

 微信截图_20190701093012.png

在内存分配和函数中,数组实际上是一种非常简单的数据类型,其工作方式与结构体相同。

切片

我们可以将切片视为基于数组的高级实现。

Go 中实现了切片,以涵盖开发人员在处理列表时面临的一些非常常见的需求,例如需要动态修改大小。

声明切片几乎与声明数组相同,除了需要必须省略长度的说明符:

slice := []int{4, 5, 3} 复制代码

仅仅看代码的话,切片和数组看起来非常相似,但实际上在实现和使用方面存在显著差异。

内存表示

切片的分配方式与数组不同,实际上是修改过的指针。每个切片包含三条信息:

指向数据序列的指针 长度:表示当前包含的元素总数。容量:即配置的内存位置总数。

 微信截图_20190701093024.png

然后,可以为彼此的值分配不同长度的切片。它们的类型相同,指针,长度和容量都在变化:

slice1 := []int{6, 1, 2} slice2 := []int{9, 3} // 可以将任何长度的切片分配给其他切片 复制代码

与数组不同,切片在初始化期间不分配数据块的内存。实际上,切片用nil值初始化。

引用传递

将切片分配给另一个变量时,仍然按值传递。这里的值仅指代指针,长度和容量,而不是元素本身占用的内存。

 微信截图_20190701093039.png

增加新元素

要向切片添加元素,通常使用append函数。

nums := []int{8, 0} nums = append(nums, 8) 复制代码

在内部,这会将指定的值分配给新元素,并返回一个新的切片。这个新切片的长度增加了1。

 微信截图_20190701093103.png

这就是为什么经常建议创建一个预先指定长度和容量的切片(特别是如果你很清楚它的大小可能是多少):

arr := make([]int, 0, 5) // 这将创建一个长度为 0 且容量为 5 的切片 复制代码 数组和切片的使用场景

数组和切片是完全不同的,因此,它们的用例也是完全不同的。

我们来看一下开源项目和 Go 标准库中的一些例子,看看它们怎么使用的。

例子 1:UUID

UUID是 128 位数据,通常用来唯一标记对象或实体。通常以短划线分隔的十六进制值表示:

e39bdaf4-710d-42ea-a29b-58c368b0c53c 复制代码

Google 的 UUID 库中,UUID 表示为 16 字节的数组:

type UUID [16]byte 复制代码

这是有意义的,因为我们知道 UUID 是由 128 位(16 字节)组成的。我们不会在 UUID 中添加或删除任何字节,因此使用数组来表示会更好。

例子 2:整数排序

在下一个示例中,我们将查看排序标准库中的sort.Ints函数:

s:= []int{5, 2, 6, 3, 1, 4} // unsorted sort.Ints(s) fmt.Println(s) // [1 2 3 4 5 6] 复制代码

sort.Ints函数接受一个整数列表并将它们排序。这里选切片有两个原因:

未指定整数的数量(可以有任意数量的整数进行排序)。这些数字需要原地排序。使用数组会将整个整数列表作为值传递,因此该函数只会对它的副本进行排序,而不是对传递给它的值。(译者注:因为不同长度的数组是不同的类型,所以 sort.Ints 规定了入参类型为切片,这也是一个比较重要的原因)结论

现在我们已经介绍了数组和切片之间的关键差异及其用例,这里有一些提示可以决定哪种结构更合适:

如果实体由一组固定长度的非空项组成:使用数组。需要对列表进行添加或删除元素时,请使用切片。如果列表可以包含任意数量的元素,请使用切片。你会以某种方式修改列表吗?如果是,则使用切片

我们可以看到,切片涵盖了在 Go 中创建应用程序的大多数场景。尽管如此,数组确实有它们的位置,并且在需要它们时非常有用。

以上就是今天给大家介绍的Golang中的数组和切片指南,如果你还想了解更多关于golang的知识技巧,可以持续关注我们http://www.fastgolang.com

本文地址:http://fastgolang.com/88.html
版权声明:本文为原创文章,版权归 go教练 所有,欢迎分享本文,转载请保留出处!

 发表评论


表情

还没有留言,还不快点抢沙发?