去切片长度是容量-1,为什么?

时间:2015-07-28 19:40:28

标签: arrays go slice

考虑下面的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)

OUPUTS:

2
3
[orange mango]

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

如果tasty_fruits的容量是3,为什么:

tasty_fruits[2] = "nectarine"

结果:

panic: runtime error: index out of range

4 个答案:

答案 0 :(得分:9)

这一行:

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)编制索引:spec:Index expressions

  

对于a切片类型Sa[x]

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

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

即使容量允许,也无法将切片索引超出切片的长度。如果重新切片,则只能到达超出长度的元素,例如:

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

输出:

["orange" "mango" "nectarine"]

答案 1 :(得分:0)

切片的容量取决于底层数组的大小。 因此,如果您将fruits更改为具有差异大小,例如:

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

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

因此容量意味着切片的最大尺寸可以扩展到。 &#34;切片不能超出其容量。试图这样做会导致运行时恐慌&#34;。

切片基本上是带有边界检查的c指针。切片的长度是它在运行时检查的边界。因此,如果您尝试访问超出长度的任何内容,也会导致运行时出现紧急情况。

是的长度&lt; =容量总是如此。

有关详情,请参阅Go Slices: usage and internals

答案 2 :(得分:-1)

如此处所述:http://blog.golang.org/slices&#34;容量字段记录底层数组实际拥有的空间大小;它是长度可以达到的最大值。试图使切片超出其容量将超出阵列的极限并引发恐慌。&#34;

答案 3 :(得分:-2)

您正在创建容量为3的切片(因为[1:3]可能包含3个元素:1,2和3)。但是,由于要复制的切片不包含3上的元素,因此仅复制1和2。