Sibainu Relax Room

愛犬の柴犬とともに過ごす部屋

GO フルスライス式を調べる

桜が満開だ。あ、いい子がいるぞとチラ見している柴犬です。

概要

私は、GO言語の教科書にオライリー・ジャパン「初めてのGo言語」を使っています。

その中で、「例3-8 フルスライス式」に理解に戸惑いを感じましたので、調べて理解したところを記事にしました。

GO フルスライス式の定義

これは、めったに使用されない のスライス範囲表記方法で、次のような感じらしいです。

<slice>[<low>:<high>:<capacity>]

または

<slice>[<low>:<high>:<max>]

感じらしいというのも、公式ページでは見つけることができませんでしたのでこういう表現にしました。

スライスのコピーを作成するには、これを使い次のようにするのが最もメモリ効率の高い方法のようです。

 s1 := []int{1, 2, 3, 4, 5}
 s2 := append(s1[:0:0], s1...)

自己流の解釈

「初めてのGo言語」の「例3-7 さらに複雑なスライスとappendの組み合わせ」を今一つ進めて次のコードを実行してみました。

copy

package main

import "fmt"

func main(){
        a := make([]int, 0, 9)
        a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)
        b := a[:3]
        c := a[3:6]
        d := a[6:]
        fmt.Println(cap(a), cap(b), cap(c), cap(d))
        d = append(d, 30, 40, 50)
        c = append(c, 60)
        b = append(b, 70, 80, 90, 100)
        a = append(a, 110)
        fmt.Println("a:", a)
        fmt.Println("b:", b)
        fmt.Println("c:", c)
        fmt.Println("d:", d)
        fmt.Println(cap(a), cap(b), cap(c), cap(d))
}

カレント内のファイルを実行するときは ./ を付け、./my-app とします。

次のような出力になりました。

これをどのようにして解釈していいのか考えてみました。図にまとめてみると次のようになりました。

b、c、dのようにスライスのサブスライス(スライスの一部)を取得しても、容量の最後まで参照している。

特に、dのように容量を超える追加があると参照ではなく、新たにスライス(長さに応じた容量で)のコピーを作成する。

といったことを推測しました。

結論

たまたま、dがフルスライス式の効果を見ることができるものとなりました。

フルスライス式を使うと次のようになります。

d := a[6:8:8]
d = append(d, 30, 40, 50)

または

d := append(a[6:8:8], 30, 40, 50)

フルスライス式の効用は

フルスライス式はスライスのコピーの作成に使う

と自分の結論です。次の画像が実行してみた結果です。

copy

package main

import "fmt"

func main(){
        a := make([]int, 0, 9)
        a = append(a, 1, 2, 3, 4, 5, 6, 7, 8)
        b := a[:3]
        c := a[3:6]
        d := a[6:8:8]
        fmt.Println(cap(a), cap(b), cap(c), cap(d))
        d = append(d, 30, 40, 50)
        c = append(c, 60)
        b = append(b, 70, 80, 90, 100)
        a = append(a, 110)
        fmt.Println("a:", a)
        fmt.Println("b:", b)
        fmt.Println("c:", c)
        fmt.Println("d:", d)
        fmt.Println(cap(a), cap(b), cap(c), cap(d))
}

カレント内のファイルを実行するときは ./ を付け、./my-app とします。