新しい本が出ていたので、凝りもせずに買ってしまった。Go の勉強が落ち着いたら、改めて Haskell をやってみよう。
日: 2017年10月14日
スライス(2)
スライスは make
関数を使っても生成できる。
変数名 := make([]型, 大きさ, 容量)
「大きさ」と「容量」があるけど、「大きさ」は要素の数(ここではゼロ値に初期化される)、「容量」はメモリ上に確保される領域のサイズのこと、と言ったらいいかな。「容量」は省略できる。
「大きさ」、「容量」はそれぞれ len
関数、cap
関数で得ることができる。
package main import "fmt" func main() { a := make([]int, 5, 10) fmt.Println(a) fmt.Println(len(a)) fmt.Println(cap(a)) }
^o^ > go run slice4.go [0 0 0 0 0] 5 10
スライスは、append
関数を使って末尾に要素を追加できる。
package main import "fmt" func main() { a := make([]int, 0) fmt.Println(a) for i := 0; i < 5; i++ { a = append(a, i) fmt.Println(a) } }
^o^ > go run slice5.go [] [0] [0 1] [0 1 2] [0 1 2 3] [0 1 2 3 4]
容量を超えて要素を追加しようとすると、スライスはよりを大きい容量の新しいメモリ領域を確保する。これは自動的に行われる。ちょっと試してみよう。
package main import "fmt" func main() { a := make([]int, 0) fmt.Printf("len=%d cap=%d %p %v\n", len(a), cap(a), a, a) for i := 1; i < 18; i++ { a = append(a, i) fmt.Printf("len=%d cap=%d %p %v\n", len(a), cap(a), a, a) } }
^o^ > go run slice6.go len=0 cap=0 0x526b88 [] len=1 cap=1 0xc0420381d8 [1] len=2 cap=2 0xc042038220 [1 2] len=3 cap=4 0xc04203e500 [1 2 3] len=4 cap=4 0xc04203e500 [1 2 3 4] len=5 cap=8 0xc042040140 [1 2 3 4 5] len=6 cap=8 0xc042040140 [1 2 3 4 5 6] len=7 cap=8 0xc042040140 [1 2 3 4 5 6 7] len=8 cap=8 0xc042040140 [1 2 3 4 5 6 7 8] len=9 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9] len=10 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9 10] len=11 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9 10 11] len=12 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9 10 11 12] len=13 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9 10 11 12 13] len=14 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9 10 11 12 13 14] len=15 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15] len=16 cap=16 0xc042052180 [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] len=17 cap=32 0xc042032100 [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
%p
は変数のポインタを表す書式指定子。上の例を見ると、大きさ(len)が容量(cap)を超えるタイミングで容量も大きくなり、同時にポインタの値も変化していく様子が見て取れる。