Go切片的长度是容量减1,为什么?

huangapple go评论87阅读模式
英文:

Go slice length is capacity -1, why?

问题

考虑下面的Go代码:

fruits := [4]string{"apple", "orange", "mango"}
tasty_fruits := fruits[1:3]
fmt.Println(len(tasty_fruits))
fmt.Println(cap(tasty_fruits))
fmt.Println(tasty_fruits)

输出结果:

2
3
[orange mango]

我不明白的是为什么tasty_fruits的容量是3,直觉上我会期望它的容量是2,因为这是切片的长度。

而且如果tasty_fruits的容量是3,为什么执行以下代码:

tasty_fruits[2] = "nectarine"

会导致以下错误:

panic: runtime error: index out of range
英文:

Consider the go code below:

fruits := [4]string{"apple", "orange", "mango"}
tasty_fruits := fruits[1:3]
fmt.Println(len(tasty_fruits))
fmt.Println(cap(tasty_fruits))
fmt.Println(tasty_fruits)

Ouputs:

2
3
[orange mango]

What I don't understand is why is the capacity of tasty_fruits 3, intuitively I would expect it to be 2 since that is the length of the slice?

And if the capacity of tasty_fruits is 3 why does:

tasty_fruits[2] = "nectarine"

result in:

panic: runtime error: index out of range

答案1

得分: 10

这行代码:

fruits := [4]string{"apple", "orange", "mango"}

创建了一个数组,而不是切片。它有4个元素,即使你只提供了3个。fmt.Printf("%q", fruits)的输出结果是:

["apple" "orange" "mango" ""]

对它进行切片操作:

tasty_fruits := fruits[1:3]

结果是:

["orange" "mango"]

长度:显然是2。容量呢?

容量是...切片长度和切片后面的[底层数组]长度之和。

由于在底层数组中的"mango"后面还有一个元素,容量是2 + 1 = 3

对切片(tasty_fruits)进行索引操作:规范:索引表达式

对于切片类型Saa[x]

  • 如果x在运行时超出范围,会发生运行时恐慌

如果0 <= x < len(a),则x在范围内,否则超出范围。由于len(tasty_fruits)2,索引2超出范围,因此会发生运行时恐慌。

即使容量允许,也不能超出切片的长度进行索引。只有在重新切片切片时,才能访问长度之外的元素,例如:

tasty_fruits2 := tasty_fruits[:3]
tasty_fruits2[2] = "nectarine" // 这是可以的,len(tasty_fruits2) = 3
fmt.Printf("%q", tasty_fruits2)

输出结果:

["orange" "mango" "nectarine"]
英文:

This line:

fruits := [4]string{&quot;apple&quot;, &quot;orange&quot;, &quot;mango&quot;}

Creates an array, not a slice. It has 4 elements even though you only supplied 3. Output of fmt.Printf(&quot;%q&quot;, fruits):

[&quot;apple&quot; &quot;orange&quot; &quot;mango&quot; &quot;&quot;]

Slicing it:

tasty_fruits := fruits[1:3]

Results in:

[&quot;orange&quot; &quot;mango&quot;]

Length: obviously 2. Capacity?

> The capacity is ... the sum of the length of the slice and the length of the [underlying] array beyond the slice.

Since there is one element after &quot;mango&quot; in the underlying array, capacity is 2 + 1 = 3.

Indexing the slice (tasty_fruits): spec: Index expressions:

> For a of slice type S: a[x]
>
> - if x is out of range at run time, a run-time panic occurs

x is in range if 0 &lt;= x &lt; len(a), otherwise it is out of range. Since len(tasty_fruits) is 2, the index 2 is out of range, and therefore runtime panic occurs.

You can't index the slice beyond the length of the slice, even if capacity would allow it. You can only reach the elements beyond the length if you reslice the slice, e.g.:

tasty_fruits2 := tasty_fruits[:3]
tasty_fruits2[2] = &quot;nectarine&quot; // This is ok, len(tasty_fruits2) = 3
fmt.Printf(&quot;%q&quot;, tasty_fruits2)

Output:

[&quot;orange&quot; &quot;mango&quot; &quot;nectarine&quot;]

答案2

得分: 0

一个切片的容量取决于底层数组的大小。
所以如果你改变 fruits 的大小,例如:

fruits := [5]string{"apple", "orange", "mango"}

cap(tasty_fruits) 将返回 4 而不是 3。

所以容量指的是切片可以扩展到的最大大小。"切片不能超过其容量进行扩展。尝试这样做将导致运行时错误"。

切片本质上是带有边界检查的 c 指针。切片的长度是运行时进行边界检查的依据。因此,如果你尝试访问超出长度的任何内容,也会导致运行时错误。

是的,长度小于等于容量始终为真。

更多详细信息,请阅读Go Slices: usage and internals

英文:

The capacity of a slice depends on the size of the underlying array.
So if you change fruits to have a difference size, for example:

fruits := [5]string{&quot;apple&quot;, &quot;orange&quot;, &quot;mango&quot;}

cap(tasty_fruits) will return 4 instead of 3.

So capacity means the maximum size of the slice can be extended to. "A slice cannot be grown beyond its capacity. Attempting to do so will cause a runtime panic".

And slices are essentially c pointers with boundary check. The length of a slices, is the boundary it will check during run time. As a result, if you try to access anything beyond length, a runtime panic will also be caused.

And yes length <= capacity is always true.

For more details please read Go Slices: usage and internals

答案3

得分: -1

根据这里的文档:http://blog.golang.org/slices,“容量”字段记录了底层数组实际拥有的空间;它是长度可以达到的最大值。试图将切片扩展到超出其容量的范围将超出数组的限制,并触发 panic 异常。

英文:

As documented here: http://blog.golang.org/slices "The Capacity field records how much space the underlying array actually has; it is the maximum value the Length can reach. Trying to grow the slice beyond its capacity will step beyond the limits of the array and will trigger a panic."

答案4

得分: -2

你正在创建一个容量为3的切片(因为[1:3]可以包含3个元素:1、2和3)。但是由于你复制的切片中没有第3个元素,所以只有1和2被复制。

英文:

You are creating a slice with the capacity of 3 (because [1:3] could contain 3 elements: 1,2 and 3). But as the slice you are copying from does not contain an element on 3, only 1 and 2 are copied.

huangapple
  • 本文由 发表于 2015年7月29日 03:40:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/31685620.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定