質問: s[2:] //(4) printSlice(s) //(4) } func printSlice(s []int) { fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) } --- で、実行結果がこれです。 len=6 cap=6 [2 3 5 7 11 13] //(1) len=0 cap=6 [] //(2) len=4 cap=6 [2 3 5 7] //(3) len=2 cap=4 [5 7] //(4) コードの(1)、(2)、(4)は理解できます。 (3)がわかりません。 (1)変数sを定義し、lengthが6、capacityが6のsliceをsに代入する。sは[2 3 5 7 11 13]。 (2)sを[:0]でスライスして、sに再代入する。lengthが0、capacityが6になる。sは[]。 (3)sを[:4]でスライスして、sに再代入する。 疑問:(2)でsliceのlengthが0になりました。そのsliceを[:4]でスライスして、なぜ実行結果が len=4 cap=6 [2 3 5 7] になるんでしょうか?なぜ中身が復活してくるのでしょうか? (4)sを[2:]でスライスして、sに再代入する。lengthが2、capacityが4になる。sは[5 7]。 (2)のコードがなく、(1)→(3)→(4)の順に実行されていれば理解できるのですが... 教えていただけると幸いです。
回答: スライスは、 * 実体の配列(C言語の配列と同じ概念) * どの区間にアクセスするのかを示すメタデータ という二重管理の仕組みになっています。 詳しくはこちらを参照してください。 メタデータは以下の三要素 * 配列の要素へのポインタ * スライス長 * 配列の容量 配列の容量が不足したら新しい配列を大きなサイズでメモリ確保して 元データ参照範囲をコピーします。 ポインタは新しい配列の先頭を指すように変更されます。 質問の例では容量が不足していないのと実体の内容が変更されていないため 以前のデータが復活したかの様になるのです。