Goのslice

Slices

Goには配列をラップして可変長配列のように使えるSliceがあります。
内部に配列へのポインタ、配列の長さ、配列の容量をもっています。
長さは組み込み関数のlenで、容量はcapで参照できます。


sliceの作成

初期化をされていない、どの配列も指していないslice。
sliceの値はnilになります。


var s0 []int
s1 := []int{}

sliceが指す配列を同時に作る場合


var s0 = []int{0,1,2}
s1 := []int{0,1,2}

既に存在するarrayをslicingする場合

array名の後に"[]"を付ける。


a := [5]int{0,1,2,3,4}
s := a[:]    //aの全ての要素を含む

aとsは同じ領域を共有している。


a[1] = 10   //a {0,10,2,3,4}
s[1] == 10  //true
            // s {0,10,2,3,4}

範囲を指定するときは"[]"内に最初の要素と最後の要素の"次"の数を:で区切って指定する。


[low:high]
[2:4]   //2番目から3番目まで

low又はhighを省略すると最初又は最後までになる。


a := [5]int{0,1,2,3,4}
s0 := a[1:3] //{1,2}
s1 := a[:2] //{0,1}
s2 := a[2:] //{2,3,4}

既に存在するsliceをslicingする場合。

arrayをslicingする場合と同じ。
slicing元と先は同じ配列を共有すしている。


a := [5]int{0,1,2,3,4}
s0 := a[1:5] //{1,2,3,4}
s1 := s0[1:3] //{2,3}
s2: = s1   //{2,3}

sliceをslicingしたり代入でコピーするとsliceが指す配列そのものはコピーされずに、配列へのポインタ、長さ、容量がコピーされる。
コピー先のsliceを使って要素を変更すると、コピー元が参照する配列の要素を変更することになる。
関数へ引数でsliceを渡して要素を変更し、呼び出し元で結果を受け取ることができる。
ただし後で述べるappendを使うと、容量が足りない場合に新しく配列が割り当てられて、元のsliceと別の配列を指すようになることがあるので注意。


make

要素数と容量を指定でき、要素をゼロ値で初期化します。
sliceの要素数を拡張するときに容量を超えない限り同じ配列を使えるので、あらかじめ拡張する要素数がわかる場合は容量を指定すると、配列の無駄な再確保がなくなります。
容量を省略すると、容量は要素数と同じになります。


make(型, 要素数, 容量)

a: = make([]int, 10, 20)  //intのスライスを要素数10、容量20でゼロ値で初期化

append

sliceの末尾に指定した要素を追加したsliceを返します。
容量を超える場合は、要素が全部入る配列を新たに作成して元の要素と追加する要素をコピーした新しいsliceを返します。


slice = sappend(slice, 要素)

複数の要素を渡せます。


slice = sappend(slice, 要素0, 要素1, 要素2)

sliceにsliceを追加することもできます。
追加するsliceの後に"..."を付けます。


slice0 = sappend(slice0, slice1...)

sliceが内部でポイントする配列が変わる場合があるためにappendはsliceを返すので必ずこれを元のsliceに代入するようにします。
関数にsliceを値渡して関数内でappendすると、呼び出しのsliceと別の配列をポイントするようになり結果を受け取られなくなります。
結果を受け取るためにはsliceを関数の返値で返すか、参照渡しをすれば可能です。


slicingによる要素数の拡張

slicingで元のsliceの要素数を超える要素数を指定することで要素数を拡張できます。
ただし容量を超える要素数を指定するとランタイムエラーが発生します。


s1 := s0[2:4] //s1{2,3}
s2 := s1[:3]  //s2{2,3,4}
s3 := s1[:4]  //runtime error

copy

sliceの要素をコピーします。
コピー先の要素数がコピー元より少ない場合はコピー先の要素数分だけコピーされます。


copy(コピー先, コピー元)

s0 := []int{0,1,2,3,4}
s1 := make([]int, 3, 5)
copy(s1, s0) //s1{0,1,2}

コピー元とコピー先が同じ配列を指し、さらにコピー領域が重なる場合でも正しくコピーされます。


s0 := []int{1,2,3,4,5}
s1 := s0[2:]    //s1{3,4,5}
copy(s1, s0)
fmt.Println(s0, s1) //[1 2 1 2 3] [1 2 3]

len

sliceの要素数を得られます。

cap

sliceの容量を得られます。


s:=make([]int,5,10)
sLen := len(s) //sLen == 5
sCap := cap(s) //sCap == 10
s0 := s[3:5]
s0Len := len(s) //s0Len == 2
s0Cap := cap(s) //s0Cap == 7

sliceの参照外の要素はガベージコレクションされない。

sliceで切り取った範囲外の要素はガベージコレクションされません。
ガベージコレクションを実行させるためにはポインタの場合はnilを代入しておく必要があります。

この記事へのコメント

最近のトラックバック