切片可以访问另一个超出范围的切片,但是索引超出范围会导致恐慌。

3

我的代码:

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

我的问题:

为什么可以访问b[4:7],虽然索引4超出了长度为3的b的范围,但访问b[4]就不行?哪些Go语言规则解释了这种行为?


1
为什么会有踩票?我该怎么做才能让这个问题更好? - Lone Learner
为什么有一个关闭投票的理由是“无法重现或由打字错误引起”?我的问题哪一部分是无法重现的? - Lone Learner
1个回答

7
相关规则:规范:索引表达式规范:切片表达式
简而言之,在进行索引时,索引必须小于长度。在进行切片时,上限索引必须小于等于容量
当进行索引时:a[x]

如果0 <= x < len(a),则索引x有效的,否则为无效的

当进行切片时:a[low: high]

对于数组或字符串,如果0 <= low <= high <= len(a),则索引有效,否则为无效对于切片,上限索引边界是切片容量cap(a)而不是长度。

当你这样做时:
b := a[1:4]
b 将是一个与 a 共享底层数组的切片,b 的长度将为 3,其容量将为 9。所以稍后可以完全合法地对 b 进行切片操作,即使超出其长度,直到其容量为 9。但是在索引时,你只能访问由切片长度所覆盖的一部分。
我们使用索引来访问切片或数组的当前元素,并且如果我们想创建数组或切片的一部分或者想要扩展它,我们使用切片操作。扩展它意味着我们需要更大的切片(但仍然被底层数组所覆盖)。

1
@lone-learner, 请务必阅读以下内容:这篇文章,然后是这篇文章,这样你就完全掌握了切片的知识。 - kostix
icza, kostix:感谢您提供规范和Go博客的链接。我仍在从《Go之旅》(https://tour.golang.org/)学习Go语言。在成功完成该教程后,我也会阅读您提供的链接。 - Lone Learner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接