55765


a tour of go を読み進めています。

[code]

    var s []int
    s = append(s, 0)
    println(cap(s))
    
[/code]

これが 2 になる理由が分かりません。


CC BY-SA 4.0
2019-06-13T16:18:08.177
55764
2019-06-13T16:49:54.297
12896
question
go
go の slice の cap が分からない


まず、length と capacity の違いに気を付けてください。`len(s)` は実際の `s` の長さ、`cap(s)` はスライス `s`
を実装するために内部的に準備している配列の長さです。`cap(s)` がいくつになるかは実装依存であり `len(s)`
以上であれば良いので、あくまで仕様にしたがうだけなら「たまたまそういう実装だったから」というのが回答になります。

> The array underlying a slice may extend past the end of the slice. The
> _capacity_ is a measure of that extent: it is the sum of the length of the
> slice and the length of the array beyond the slice; a slice of length up to
> that capacity can be created by _slicing_ a new one from the original slice.
> The capacity of a slice `a` can be discovered using the built-in function
> `cap(a)`.
>
> <https://golang.org/ref/spec#Slice_types>

ではどういう実装になっているのでしょうか。この回答が投稿された時点での Go の master
ブランチの実装では、[この部分のコード](https://github.com/golang/go/blob/25a2b98f7a1454aac0d7d3072f74613ac0446630/src/runtime/slice.go#L76)が
capacity を増やしています。特に以下のコードを読めば、今回のコードで `cap(s)` が `2` になっていた理由が分かります。

[code]

    newcap := old.cap
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        if old.len < 1024 {
            newcap = doublecap
        } else {
            // Check 0 < newcap to detect overflow
            // and prevent an infinite loop.
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            // Set newcap to the requested cap when
            // the newcap calculation overflowed.
            if newcap <= 0 {
                newcap = cap
            }
        }
    }
    
[/code]

というわけで Go コンパイラ自体の実装まで遡って回答すると「スライスの length が小さい場合、append したときの capacity は元の 2
倍以上になるように実装されてるから」となります。


CC BY-SA 4.0
2019-06-13T16:49:54.297
55765
2019-06-13T16:49:54.297
19110
55764
answer