片可以访问超出范围的另一个片,但索引超出范围会引起恐慌

时间:2020-08-11 15:59:12

标签: go slice indexoutofboundsexception semantics

我的代码:

package main

import (
    "fmt"
)

func main() {
    a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    b := a[1:4]
    fmt.Println("a:", a)
    fmt.Println("b:", b)
    
    // Works fine even though c is indexing past the end of b.
    c := b[4:7]
    fmt.Println("c:", c)
    
    // This fails with panic: runtime error: index out of range [4] with length 3
    // d := b[4]
}

输出:

a: [0 1 2 3 4 5 6 7 8 9]
b: [1 2 3]
c: [5 6 7]

如果我取消注释包含d := b[4]的行,则会导致此错误:

panic: runtime error: index out of range [4] with length 3

我的问题:

为什么即使索引4超出了长度为3的b[4:7]的索引4,但访问b的索引4却超出范围,为什么仍可以访问b[4]?什么Go语言规则解释了这种行为?

1 个答案:

答案 0 :(得分:7)

相关规则:Spec: Index expressionsSpec: Slice expressions

简而言之:建立索引时,索引必须小于 length 。切片时,上限索引必须小于或等于容量

索引时:a[x]

如果x,索引0 <= x < len(a)在范围内 ,否则超出范围

切片时:a[low: high]

对于数组或字符串,如果0 <= low <= high <= len(a),则索引在范围内,否则,它们在范围之外对于切片,索引的上限是切片容量cap(a)而不是长度。

执行此操作时:

b := a[1:4]

b是一个切片,与a共享后备阵列,b的长度为3,容量为9。因此,以后将b切成甚至超过其长度,直至达到其容量9都是完全有效的。但是,在编制索引时,您始终只能索引切片长度所覆盖的部分。

我们使用索引来访问切片或数组的当前元素,如果要创建数组或切片的片段,或者如果要扩展,则使用切片。扩展它意味着我们想要更大的一部分(但仍由后备阵列覆盖)。