- 原文地址:www.sohamkamani.com/blog/golang…
- 原文做者:Soham Kamani
- 译文地址:github.com/watermelo/d…
- 译者:咔叽咔叽
- 译者水平有限,若有翻译或理解谬误,烦请帮忙指出
首先,很容易看到数组和切片好像是同一个东西:表示列表的数据结构。然而,它们实际上彼此彻底不一样。git
在这篇文章中,咱们将探讨他们在 Go 中的差别和实现。github
数组是固定的数据列表。这里的重点是固定的,由于一旦设置了数组的长度,它就没法更改。golang
咱们举一个声明了四个整数的数组的例子:数组
arr := [4]int{3, 2, 5, 4}
复制代码
咱们在上面的例子中定义的 arr
变量的类型是 [4] int
,它是一个大小为 4 的数组。这里须要注意的是,4
包含在类型定义中。数据结构
这意味着两个不一样长度的数组其实是两个不一样的类型。因此不能将不一样长度的数组视为一种类型,也不能将其中一个的值分配给另外一个:app
longerArr := [5]int{5, 7, 1, 2, 0}
longerArr = arr
// 会抛出编译错误
longerArr == arr
// 会抛出编译错误
复制代码
我发现考虑数组的一个好方法就是结构体。若是咱们能够构造数组等价的结构体,它可能看起来像这样:ide
// 长度为 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
块的序列:post
初始化数组类型的变量后,将当即分配此内存。ui
在 Go 中,没有引用传递。一切都是经过值传递的。若是将数组的值分配给另外一个变量,则会复制整个值。
若是只想将“引用”传递给数组,可使用指针:
在内存分配和函数中,数组其实是一种很是简单的数据类型,其工做方式与结构体相同。
咱们能够将切片视为基于数组的高级实现。
在 Go 中实现了切片,以涵盖开发人员在处理列表时面临的一些很是常见的需求,例如须要动态修改大小。
声明切片几乎与声明数组相同,除了须要必须省略长度的说明符:
slice := []int{4, 5, 3}
复制代码
仅仅看代码的话,切片和数组看起来很是类似,但实际上在实现和使用方面存在显著差别。
切片的分配方式与数组不一样,其实是修改过的指针。每一个切片包含三条信息:
而后,能够为彼此的值分配不一样长度的切片。它们的类型相同,指针,长度和容量都在变化:
slice1 := []int{6, 1, 2}
slice2 := []int{9, 3}
// 能够将任何长度的切片分配给其余切片
复制代码
与数组不一样,切片在初始化期间不分配数据块的内存。实际上,切片用 nil
值初始化。
将切片分配给另外一个变量时,仍然按值传递。这里的值仅指代指针,长度和容量,而不是元素自己占用的内存。(译者注:这里作了一个实验能够更清晰地了解这个过程)
要向切片添加元素,一般使用 append
函数。
nums := []int{8, 0}
nums = append(nums, 8)
复制代码
在内部,这会将指定的值分配给新元素,并返回一个新的切片。这个新切片的长度增长了 1。(译者注:关于切片的扩容分析能够参考煎鱼和 stefno 的博客)
这就是为何常常建议建立一个预先指定长度和容量的切片(特别是若是你很清楚它的大小多是多少):
arr := make([]int, 0, 5)
// 这将建立一个长度为 0 且容量为 5 的切片
复制代码
数组和切片是彻底不一样的,所以,它们的用例也是彻底不一样的。
咱们来看一下开源项目和 Go 标准库中的一些例子,看看它们怎么使用的。
UUID 是 128 位数据,一般用来惟一标记对象或实体。一般以短划线分隔的十六进制值表示:
e39bdaf4-710d-42ea-a29b-58c368b0c53c
复制代码
在 Google 的 UUID 库 中,UUID 表示为 16 字节的数组:
type UUID [16]byte
复制代码
这是有意义的,由于咱们知道 UUID 是由 128 位(16 字节)组成的。咱们不会在 UUID 中添加或删除任何字节,所以使用数组来表示会更好。
在下一个示例中,咱们将查看排序标准库中的 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
函数接受一个整数列表并将它们排序。这里选切片有两个缘由:
如今咱们已经介绍了数组和切片之间的关键差别及其用例,这里有一些提示能够决定哪一种结构更合适:
咱们能够看到,切片涵盖了在 Go 中建立应用程序的大多数场景。尽管如此,数组确实有它们的位置,而且在须要它们时很是有用。
大家有更好的例子吗?若是有任何关于你更喜欢切片胜于数组(反之亦然)的例子?请在下面的评论中告诉咱们👇