A Tour of Goのざっくりまとめ④ <More types: 配列(Arrays), Slice, make編>
前回までの続きです。
mattsun-plapla.hatenablog.com
mattsun-plapla.hatenablog.com
mattsun-plapla.hatenablog.com
配列
[n]T 型は、型 T の n 個の変数の配列( array )を表します。
func main() { var a [2]int a[0] = 300 a[1] = 500 fmt.Println(a) // [300 500] // 定めたインデックス数以上の数を配列に配置できない a[2] = 1000 // invalid array index 2 (out of bounds for 2-element array) } /* 最初に値を入れる場合 */ func main() { var b [2]int = [2]int{500, 1000} // or c := [3]string{"a", "b", "c"} fmt.Println(b) // [500, 1000] fmt.Println(c) // [a, b, c] }
- 同じデータ型を格納する
- デフォルト値はデータ型に応じて変わる(int=0, string="", etc..)
- 配列は最初に定めたサイズを変えることができない。つまり固定長である。
- 可変長にしたい場合、後述のSliceを使う。
Automatic array length declaration
[n]Tにおけるnを定めなくとも、配列数を推論してくれるもの。
この場合、[...]Tと書く。
func main(){ i := [...]int{ 1,2,3,4, } s := [...]string{ "japan", "korea", "thailand", "usa", } fmt.Println(i) // [1 2 3 4] fmt.Println(s) // [japan korea thailand usa] }
配列同士の比較
配列同士の比較では、データ型、配列数、要素の順序が合致していないと同じとみなされない。
func main(){ a := [3]int{1,2,3} b := [3]string{"1", "2", "3"} c := [3]int{2,1,3} fmt.Println(a==b) // (mismatched types [3]int and [3]string) fmt.Println(a==c) // false }
Multi-demantional array
後述のスライスにも書いていますが、配列内配列も下記のように作れる。
ただし、配列内はすべて同じデータ型である必要がある。
[n][m]T型は、m個の要素をもつ配列がn個あることを表します。
func main(){ a := [2][3]int{ [3]int{1,2,3}, [3]int{4,5,6}, } fmt.Println(a) // [[1 2 3] [4 5 6]] /* short syntaxとしてこのようにも書ける */ a := [3][2]int{{1,2},{3,4},{5,6}} fmt.Println(a) // [[1 2] [3 4] [5 6]] }
多次元配列の要素を1つずつFor loopで取り出す場合の一例
func main(){ a := [3][2]int{{1,2},{3,4},{5,6}} for _, outsideArray := range a{ for _, insideArray := range outsideArray{ fmt.Println(insideArray) // 1,2,3,4,5,6 } } }
Slice
型 []T は 型 T のスライスを表します。
- スライスは配列への参照のようなもの
- 同じデータ型である必要はあるものの、配列内要素数の制約がない。(先述のように、異なるデータ型でもいいのはstruct)
- 可変長配列であるスライスでは、[]の中に配列数を指定しない
- 後から配列に要素を追加することもできる。また、配列内配列をつくることもできる
- インデックス指定で値を取り出す場合、最後の要素は含まれない (ex: 1:4なら1~3まで)
- スライスの要素を変更すると元の対応する配列要素も変更される
- スライスのゼロ値はnil (配列との違い。配列は定めた要素数分の初期値を返す)
また、おそらく、Pythonのように、[-1]といった取り出し方はできない模様。
スライスが配列への参照であること
スライスは配列を参照しているので、スライス自体がデータを持つのではなく、配列にあるデータをもっている。
var s []intのような、配列内にデータがない場合は、スライスは配列を参照していないため、nilが返される。
また、スライス内のある要素を書き換えた場合、その更新は元の配列へも反映される。
func main() { sl := []int{1, 2, 3, 4, 5, 6} fmt.Println(sl) // [1 2 3 4 5 6] fmt.Println(sl[1]) // 2 fmt.Println(sl[1:3]) // [2 3] fmt.Println(sl[:3]) // [1 2 3] fmt.Println(sl[3:]) // [4 5 6] /* 値を変更 */ sl[2] = 1000 fmt.Println(sl) // [1 2 1000 4 5 6] /* 値を追加 */ sl = append(sl, 5000) fmt.Println(sl) // [1 2 1000 4 5 6 5000] /* 配列に配列を追加 */ var double = [][]int{ []int{1, 2, 3}, []int{4, 5, 6}, []int{7, 8, 9}, } fmt.Println(double) // [[1 2 3] [4 5 6] [7 8 9]] }
スライス同士の比較
スライスはnilとしか比較できない。要素同士を比較したい場合、ループを回して要素を取り出すか、他のパッケージを利用するしかない。
make
built-inのmake関数をつかってスライスをつくることもできる。
The make function allocates a zeroed array and returns a slice that refers to that array
https://tour.golang.org/moretypes/13
ということで、配列と配列の容量を決めることができる。
スライスが返されるため、生成時に定めた配列を拡大することができる。
一方で、容量以上の配列を作成しようとするとエラーになる。(下記例の最後の文)
func main() { /* 2番目が配列数、3番目が配列の容量(capacity) */ s1 := make([]int, 3) fmt.Printf("len=%d cap=%d val=%v\n", len(s1), cap(s1), s1) // len=3 cap=3 val=[0 0 0] s2 := make([]int, 3, 5) fmt.Printf("len=%d cap=%d val=%v\n", len(s2), cap(s2), s2) // len=3 cap=5 val=[0 0 0] s3 = append(s3, 0, 0) fmt.Printf("len=%d cap=%d val=%v\n", len(s3), cap(s3), s3) // len=5 cap=5 val=[0 0 0 0 0] s4 = append(s4, 0, 0, 1, 2) // Sliceなのでなので定めた容量以上を追加することもOK fmt.Printf("len=%d cap=%d val=%v\n", len(s4), cap(s4), s4) // len=9 cap=10 val=[0 0 0 0 0 0 0 1 2] // s4 := make([]int, 5, 3) // error: len larger than cap in make([]int)