为什么切片长度大于容量会导致运行时错误?

huangapple go评论131阅读模式
英文:

Why slice length greater than capacity gives runtime error?

问题

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

  1. package main
  2. import "fmt"
  3. func main() {
  4. type b []int
  5. var k = make([]b, 10, 5)
  6. fmt.Println(k[8])
  7. }

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

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

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

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

英文:

Made a slice where capacity is less than the length

  1. package main
  2. import "fmt"
  3. func main() {
  4. type b []int
  5. var k = make([]b, 10, 5)
  6. fmt.Println(k[8])
  7. }

This when tried to run gives following error.

> 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

My question is can capacity be less than length?<br><br>

If 'Yes' then why this error came? <br>
And if 'No'then why this is a runtime error and why not a compile time?

答案1

得分: 19

不,容量不能小于长度。

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

对于切片s,以下不变式始终成立(除非你做了一些不安全的操作):

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

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

  1. package main
  2. import (
  3. "fmt"
  4. "rand"
  5. )
  6. func main() {
  7. k := make([]int, rand.Int(), rand.Int())
  8. fmt.Println(k)
  9. }

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

英文:

No, capacity cannot be less than length.

A slice is a reference to a part of an array. A slice's capacity represents the size of that backing array. If its length is greater than its capacity, then what memory is it using?

The following invariant always holds for a slice s (unless you've done something unsafe):

  1. 0 &lt;= len(s) &lt;= cap(s)

Your code produces a runtime error rather than a compile-time error because the error cannot always be detected statically. In your case it could be, but consider this code:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;rand&quot;
  5. )
  6. func main() {
  7. k := make([]int, rand.Int(), rand.Int())
  8. fmt.Println(k)
  9. }

The values passed to make cannot be known until runtime.

答案2

得分: 7

阅读Go编程语言规范

> 长度和容量
>
> 切片的容量是底层数组中分配空间的元素数量。在任何时候,以下关系成立:
>
> 0 <= len(s) <= cap(s)

英文:

Read the Go Programming Language Specification.

> 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:
>
> 0 <= len(s) <= cap(s)

答案3

得分: 0

检查长度和容量,如果长度小于0或长度大于容量,则会引发恐慌。

英文:

check the runtime/slice.go

  1. func makeslice(et *_type, len, cap int) unsafe.Pointer {
  2. mem, overflow := math.MulUintptr(et.size, uintptr(cap))
  3. if overflow || mem &gt; maxAlloc || len &lt; 0 || len &gt; cap {
  4. // NOTE: Produce a &#39;len out of range&#39; error instead of a
  5. // &#39;cap out of range&#39; error when someone does make([]T, bignumber).
  6. // &#39;cap out of range&#39; is true too, but since the cap is only being
  7. // supplied implicitly, saying len is clearer.
  8. // See golang.org/issue/4085.
  9. mem, overflow := math.MulUintptr(et.size, uintptr(len))
  10. if overflow || mem &gt; maxAlloc || len &lt; 0 {
  11. panicmakeslicelen()
  12. }
  13. panicmakeslicecap()
  14. }
  15. return mallocgc(mem, et, true)
  16. }

it will check the len and the cap, and give a panic if len<0 or len>cap.

huangapple
  • 本文由 发表于 2011年8月17日 03:07:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/7083623.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定