关于go:为什么切片长度大于容量会产生运行时错误?


Why slice length greater than capacity gives runtime error?

在容量小于长度的地方做一个切片

1
2
3
4
5
6
7
8
9
10
11
    package main

    import fmt"fmt"

    func main(){

     type b []int
     var k = make([]b, 10, 5)
     fmt.Printf("%d
",k[8])
     }

尝试运行时出现以下错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    panic: runtime error: makeslice: cap out of range

    runtime.panic+0x9e /go/src/pkg/runtime/proc.c:1060
            runtime.panic(0x453b00, 0x30020390)
    runtime.panicstring+0x94 /go/src/pkg/runtime/runtime.c:116
            runtime.panicstring(0x4afd6c, 0x40d80c)
    runtime.makeslice+0x70 /go/src/pkg/runtime/slice.c:24
            runtime.makeslice(0x44302c, 0xa, 0x0, 0x5, 0x0, ...)
    main.main+0x45 C:/GOEXCE~1/basics/DATATY~1/slice.go:8
            main.main()
    runtime.mainstart+0xf 386/asm.s:93
            runtime.mainstart()
    runtime.goexit /go/src/pkg/runtime/proc.c:178
            runtime.goexit()
    ----- goroutine created by -----
    _rt0_386+0xbf 386/asm.s:80

我的问题是容量能小于长度吗?

如果"是",那么为什么会出现此错误?如果"否",那么为什么这是一个运行时错误,为什么不是编译时?


不,容量不能小于长度。

切片是对数组一部分的引用。切片的容量表示该支持数组的大小。如果它的长度大于它的容量,那么它使用的内存是什么?

以下不变量始终适用于切片(除非您做了不安全的事情):

1
0 <= len(s) <= cap(s)

您的代码会产生运行时错误,而不是编译时错误,因为不能总是静态地检测到该错误。在您的情况下,它可能是,但请考虑以下代码:

1
2
3
4
5
6
7
8
9
10
11
package main

import (
   "fmt"
   "rand"
)

func main() {
    k := make([]int, rand.Int(), rand.Int())
    fmt.Println(k)
}

传递给make的值在运行时之前无法知道。


阅读GO编程语言规范。

Length and capacity

The capacity of a slice is the number of elements for which there is
space allocated in the underlying array. At any time the following
relationship holds:

1
0 <= len(s) <= cap(s)