如何在如何在Go中使用切片容量和长度中使用切片容量和长度
来做一个快速测验-以下代码输出什么?
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals = append(vals, i)
}
fmt.Println(vals)
Run it on the Go Playground → https://play.golang.org/p/7PgUqBdZ6Z
如果猜到了[0 0 0 0 0 0 1 2 3 4] ,那么你是正确的。 等一下为什么不是[0 1 2 3 4]?
如果答错了,也不担心。从其他语言过渡到Go时,这是一个相当普遍的错误,在本文中,我们将介绍为什么输出不符合你的
预期以及如何利用Go的细微差别来提高代码效率。
Slices vs Arrays
在Go中,既有数组又有切片。切片和数组之间有很多区别,数组的长度是其类型的一部分,所以数组不能改变大小,而切片
可以具有动态大小,因为切片是数组的包装。这是什么意思?假设我们有一个数组var a [10]int。此数组的大小固定,无法更
改。如果我们调用len(a),它将始终返回10,因为该大小10是该类型[10]int的一部分。如果你在数组中需要10个以上的项,则必
须创建一个类型完全不同的新对象,例如var b [11] int,然后将所有值从a复制到b。
虽然在特定情况下使用具有固定大小的数组很有价值,但通常来说这并不是开发人员想要的。相反,我们希望使用与Go中的
数组类似的东西,但是具有随着时间增加长度的能力。一种简单的方法是创建一个比需要的数组大得多的数组,然后将该数组
的子集当作使用的数组。下面的代码显示了一个示例。
var vals [20]int
for i := 0; i < 5; i++ {
vals[i] = i * i
}
subsetLen := 5
fmt.Println("The subset of our array has a length of:", subsetLen)
// Add a new item to our array
vals[subsetLen] = 123
subsetLen++
fmt.Println("The subset of our array has a length of:", subsetLen)
Run it on the Go Playground → https://play.golang.org/p/Np6-NEohm2
上面代码中,我们将一个数组其大小设置为20,但是由于我们仅使用一个子集,因此我们的代码可以假装数组的长度为5,然
后在向数组中添加新项后为6。
(很粗略地说)这就是切片的工作方式。它们包装一个具有设定大小的数组,就像上一个示例中的数组具有20的设定大小一
样。它们还跟踪程序可使用的数组子集-length属性,它类似于上一示例中的subsetLen变量。
切片还具有一个容量,类似于上一个示例中数组(20)的总长度。这很有用,因为它告诉你子集可以增长多大之后才能不再
适合支撑切片的底层数组。当发生这种情况时,将会分配一个新的数组来支撑切片,但是所有这些逻辑都隐藏在append函数的
后面。
简而言之,将slice与append函数结合在一起可以为我们提供一种与数组非常相似的类型,但是随着时间的增长,它可以处理更
多元素。
让我们再次看一下前面的示例,但是这次我们将使用切片而不是数组。
评论0
最新资源