4
votes

Made a slice where capacity is less than the length


    package main

    import fmt "fmt"

    func main(){

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

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?

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

3

3 Answers

16
votes

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):

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

package main

import (
    "fmt"
    "rand"
)

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

The values passed to make cannot be known until runtime.

6
votes

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)
0
votes

check the runtime/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)
}

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