为啥切片长度大于容量会产生运行时错误?

Posted

技术标签:

【中文标题】为啥切片长度大于容量会产生运行时错误?【英文标题】:Why slice length greater than capacity gives runtime error?为什么切片长度大于容量会产生运行时错误? 【发布时间】:2011-10-28 08:34:45 【问题描述】:

做了一个容量小于长度的切片

包主 导入 fmt "fmt" 函数主() 类型 b []int var k = make([]b, 10, 5) fmt.Printf("%d\n",k[8])

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

恐慌:运行时错误:makelice:上限超出范围 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() 运行时.mainstart+0xf 386/asm.s:93 运行时.mainstart() runtime.goexit /go/src/pkg/runtime/proc.c:178 运行时.goexit() ----- goroutine 创建者 ----- _rt0_386+0xbf 386/asm.s:80

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

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

【问题讨论】:

【参考方案1】:

检查运行时/slice.go

func makeslice(et *_type, len, cap int) unsafe.Pointer 
    mem, overflow := math.MulUintptr(et.size, uintptr(cap))
    if overflow || mem > maxAlloc || len < 0 || len > cap 
        // NOTE: Produce a 'len out of range' error instead of a
        // 'cap out of range' error when someone does make([]T, bignumber).
        // 'cap out of range' is true too, but since the cap is only being
        // supplied implicitly, saying len is clearer.
        // See golang.org/issue/4085.
        mem, overflow := math.MulUintptr(et.size, uintptr(len))
        if overflow || mem > maxAlloc || len < 0 
            panicmakeslicelen()
        
        panicmakeslicecap()
    

    return mallocgc(mem, et, true)

它会检查 len 和 cap,如果 lencap 会出现恐慌。

【讨论】:

如果可能的话最好链接到源 golang.org/src/runtime/slice.go 并扩展原因,以便让提问者朝着正确的方向前进,在这种情况下,了解初始条件是在运行时创建切片时。【参考方案2】:

不,容量不能小于长度。

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

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

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

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

package main

import (
    "fmt"
    "rand"
)

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

直到运行时才能知道传递给 make 的值。

【讨论】:

【参考方案3】:

阅读Go Programming Language Specification。

Length and capacity

切片的容量是有多少个元素 在底层数组中分配的空间。随时以下 关系成立:

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

【讨论】:

以上是关于为啥切片长度大于容量会产生运行时错误?的主要内容,如果未能解决你的问题,请参考以下文章

使用公式连接引用会产生运行时错误

分配给 gslice_array 会产生运行时错误

在机器级别上,应用程序以二进制形式运行,然后在发生运行时错误时,如何呈现回错误代码?

为啥我会收到运行时错误?

为啥会出现错误:类与键名的键值编码不兼容?

访问数组索引时如何强制打字稿给出错误