切片的下限和上限

问题描述 投票:0回答:3

我的代码片段

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("check 1: ",s, len(s))
    
    s = s[1:4]
    fmt.Println("check 2: ",s, len(s))

    s = s[3:5]
    fmt.Println("check 3: ",s, len(s))

    s = s[1:]
    fmt.Println("check 4: ",s, len(s))
}

输出

check 1:  [2 3 5 7 11 13] 6
check 2:  [3 5 7] 3
check 3:  [11 13] 2
check 4:  [13] 1

我的预期产出

check 1:  [2 3 5 7 11 13] 6
check 2:  [3 5 7] 3
panic: runtime error: slice bounds out of range [3:5]

s = s[1:4]
- 这里我们更新了切片变量 s,它现在包含 [3 5 7] 并且
s = s[3:5]
应该给出
out of range error
,因为索引 3 到 5 不存在于 s

的新值中

相反,为什么输出打印 - [11 13]

go slice
3个回答
4
投票

当切片容量大于切片长度时,可能会造成一些混乱。关键思想是切片是数组的视图。您无法访问超出切片边界的内容,但您可以重新切片并获得底层数组的新视图。

最初,切片长度和容量为 6。

s = s[1:4]
之后,切片长度为3,容量为5。您可以将此切片重新切片到大于3个元素,并且仍然访问底层数组的元素。

因此,

s[3:5]
是有效的,并且相当于原始切片的
[4:6]


2
投票

这是根据 golangs 切片规则。 Golangs slice 的工作方式与其他语言略有不同。当从切片或数组中取出切片时,它指向前一个数组或切片而不是复制。

                                      {2,3, 5,           7, 11, 13} //length 6
s = s[1:4] //length 3 but it points here ^ and ends here ^
           {2,3, 5,      7, 11,             13}
s = s[3:5] // it points here ^ and ends here ^

所以如果你这样做了

s = s[3:6]
它会因索引超出边界而恐慌。


1
投票

正如 golang 文档中提到的 - 切片不存储任何数据,它只是描述底层数组的一部分。 切片同时具有长度和容量。 切片的长度是它包含的元素数量。 切片的容量是基础数组中的元素数量,从切片中的第一个元素开始计数。 切片 s 的长度和容量可以使用表达式 len(s) 和 cap(s) 获得。

虽然执行 s[1:4] 后长度为

3
,但容量为 5,因此您可以从底层数组访问 s[3:5] 而不会出现索引输出错误

尝试以下代码片段以更好地理解

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    fmt.Printf("check 1: len=%d cap=%d %v\n", len(s), cap(s), s)

    s = s[1:4]
    fmt.Printf("check 2: len=%d cap=%d %v\n", len(s), cap(s), s)

    s = s[3:5]
    fmt.Printf("check 4: len=%d cap=%d %v\n", len(s), cap(s), s)

    s = s[1:]
    fmt.Printf("check 5: len=%d cap=%d %v\n", len(s), cap(s), s)
}

输出:

check 1: len=6 cap=6 [2 3 5 7 11 13]
check 2: len=3 cap=5 [3 5 7]
check 4: len=2 cap=2 [11 13]
check 5: len=1 cap=1 [13]
© www.soinside.com 2019 - 2024. All rights reserved.