Go切片长度是容量-1,为什么?
Go slice length is capacity -1, why?
考虑下面的代码:
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
这一行:
fruits := [4]string{"apple", "orange", "mango"}
创建一个数组,而不是切片。它有 4 个元素,即使你只提供了 3 个。fmt.Printf("%q", fruits)
的输出:
["apple" "orange" "mango" ""]
切片:
tasty_fruits := fruits[1:3]
结果:
["orange" "mango"]
长度:明明是2.容量?
The capacity is ... the sum of the length of the slice and the length of the [underlying] array beyond the slice.
由于底层数组"mango"
后有一个元素,容量为2 + 1 = 3
.
索引切片(tasty_fruits
):规范:Index expressions:
For a
of slice type S
: a[x]
- if
x
is out of range at run time, a run-time panic occurs
如果0 <= x < len(a)
x
在范围内,否则在范围外。由于 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"]
您正在创建一个容量为 3 的切片(因为 [1:3] 可以包含 3 个元素:1,2 和 3)。但是由于您从中复制的切片不包含 3 上的元素,因此仅复制 1 和 2。
切片的容量取决于底层数组的大小。
因此,如果您将 fruits
更改为不同的大小,例如:
fruits := [5]string{"apple", "orange", "mango"}
cap(tasty_fruits) 将 return 4 而不是 3。
所以capacity是指slice可以扩展到的最大尺寸。 "A slice cannot be grown beyond its capacity. Attempting to do so will cause a runtime panic".
而切片本质上是 c
带边界检查的指针。切片的长度是它将在 运行 时间内检查的边界。因此,如果您尝试访问超出长度的任何内容,也会导致 运行时间恐慌。
是的,长度 <= 容量始终为真。
如此处记录: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."
考虑下面的代码:
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
这一行:
fruits := [4]string{"apple", "orange", "mango"}
创建一个数组,而不是切片。它有 4 个元素,即使你只提供了 3 个。fmt.Printf("%q", fruits)
的输出:
["apple" "orange" "mango" ""]
切片:
tasty_fruits := fruits[1:3]
结果:
["orange" "mango"]
长度:明明是2.容量?
The capacity is ... the sum of the length of the slice and the length of the [underlying] array beyond the slice.
由于底层数组"mango"
后有一个元素,容量为2 + 1 = 3
.
索引切片(tasty_fruits
):规范:Index expressions:
如果For
a
of slice typeS
:a[x]
- if
x
is out of range at run time, a run-time panic occurs
0 <= x < len(a)
x
在范围内,否则在范围外。由于 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"]
您正在创建一个容量为 3 的切片(因为 [1:3] 可以包含 3 个元素:1,2 和 3)。但是由于您从中复制的切片不包含 3 上的元素,因此仅复制 1 和 2。
切片的容量取决于底层数组的大小。
因此,如果您将 fruits
更改为不同的大小,例如:
fruits := [5]string{"apple", "orange", "mango"}
cap(tasty_fruits) 将 return 4 而不是 3。
所以capacity是指slice可以扩展到的最大尺寸。 "A slice cannot be grown beyond its capacity. Attempting to do so will cause a runtime panic".
而切片本质上是 c
带边界检查的指针。切片的长度是它将在 运行 时间内检查的边界。因此,如果您尝试访问超出长度的任何内容,也会导致 运行时间恐慌。
是的,长度 <= 容量始终为真。
如此处记录: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."