【问题标题】:golang: Why the following code does NOT panic with "slice index out of range" error [duplicate]golang:为什么以下代码不会因“切片索引超出范围”错误而恐慌[重复]
【发布时间】:2017-01-07 16:02:58
【问题描述】:
package main

import "fmt"

type Point struct {
        X int
        Y int
}

type Points struct {
    P []Point
}

func main() {
    data := Points{}
    for i := 0; i < 10; i++ {
        data.P = append(data.P, Point{
            X: i,
            Y: i*2,
        })
    }
    fmt.Printf("%+v\n", data.P[5:11]);
}

上面的程序运行时,打印出来:

[{X:5 Y:10} {X:6 Y:12} {X:7 Y:14} {X:8 Y:16} {X:9 Y:18} {X:0 Y: 0}]

为什么有 {X:0, Y:0} 似乎是自动生成的,因为切片的长度是 10,但我试图得到 5:11?

我在代码中发现了问题并使用“原始”切片进行测试,例如:

package main

import "fmt"

func main() {
    v := []int{0,1,2,3,4,5,6,7,8,9}
    fmt.Printf("%v\n", v[5:11])
}

这个简单的程序会产生错误(如预期的那样):

panic: runtime error: slice bounds out of range

goroutine 1 [running]:
panic(0x47a8e0, 0xc42000a130)
        /usr/local/go/src/runtime/panic.go:500 +0x1a1
main.main()
        /home/fxr/go/src/cmhwc/test2.go:7 +0x53
exit status 2

为什么第一个程序不恐慌?

【问题讨论】:

  • 打印切片在每种情况下的容量,你就会明白为什么了。

标签: go slice


【解决方案1】:

因为当您使用 append() 将元素添加到没有更多空间添加新元素的切片时,它会创建一个新元素,复制旧元素以及您要求添加的新元素的容量翻倍返回对此的引用。再往下,当您使用切片语法询问超出切片明显末端的元素时,长度实际上应用于由 append 创建和返回的底层数组。

正如@JimB 在 cmets 中建议的那样,您可以在附加循环的每一步添加一条语句来打印容量以查看这种情况:

fmt.Println(cap(data.P))

应该生成类似的东西:

2
2
4
4
8
8
8
8
16
16

【讨论】:

  • 没错。谢谢!
  • @xrfang,不客气!
猜你喜欢
  • 2017-05-12
  • 1970-01-01
  • 2020-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 2014-11-25
相关资源
最近更新 更多