はじめに
go言語初心者のための記事です。
公式チュートリアルの大事なところをまとめただけです。
この記事では配列、および配列に似たものをまとめます。
array、slice、mapの3つです。
ややこしいGoにおける配列の概念
Goには二つの配列表現arrayとsliceがある。
とてもややこしいが、公式チュートリアル曰く、
- 固定長がarray(=配列)
- 可変長がslice
という定義らしい。
配列(array)
Goの配列(array)は必ず配列の長さを指定する。
array[i:j]という書き方でiからj前までの要素を取得できる。
var a [10]int
b := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(b[0:3]) // [2 3 5]を返す
また、b[0:6]は、b[:6]、b[0:]、b[:]という書き方と等価。
可変長な配列(slice)
python等の配列のような可変長の配列をGoではsliceと呼ぶ。
混乱を避けるためここではそれぞれarray、sliceと呼ぶこととする。
var s[]int // 空のsliceを生成
fmt.Println(s) // []を返す
array := [6]int{2, 3, 5, 7, 11, 13}
var slice[]int = array[1:4]
fmt.Println(s) // [3 5 7]を返す
arrayからsliceへと代入した場合、sliceはそのarrayの一部として振る舞う。
つまり、sliceの変更はarrayにも反映される。
日本語下手なので下記の例を見てください。
array := [6]int{2, 3, 5, 7, 11, 13}
var slice[]int = array[1:4]
slice[0] = 0
fmt.Println(slice) // [0 5 7]を返す
fmt.Println(array) // [2 0 5 7 11 13]を返す
s := []int{1, 2, 3} // :=演算子を使うとこのように書ける
多次元のslice
空行列[]の数でsliceの次元を表現できる。
slice := [][]string{
[]string{"犬", "猫", "猿"},
[]string{"りんご", "ばなな", "パイナップル"},
[]string{"男", "女", "あいつ"},
}
fmt.Println(slice[1][2]) // パイナップルを返す
sliceの長さと容量
sliceには長さ(length)と容量(capacity)という概念がある。
長さ(length)はどの言語にもよくある配列の長さのようなもの。
容量(capacity)は聞いたことなかったが考え方は簡単で、
元のarrayの長さ - arrayから取得し始めたsliceの要素のインデックス
ってだけ。
これも実行して確認するほうが理解が早い。
array := [6]int{2, 3, 5, 7, 11, 13}
var slice[]int = array[1:4]
fmt.Println(len(slice)) // 3を返す
fmt.Println(cap(slice)) // 5を返す(6-1=5)
s := []int{2, 3, 5, 7} // この定義の場合、元のarrayも{2, 3, 5, 7}となる
s = s[1:3]
fmt.Println(len(s)) // 2を返す
fmt.Println(cap(s)) // 3を返す(4-1=2)
sliceを操作する便利な関数
sliceの初期化(make)
make関数によって、全ての要素に0が代入されたsliceを生成することができる。
引数は以下のとおり。
make(型, sliceの長さ, sliceの容量)
3番目の引数であるsliceの容量のみ省略できる。
a := make([]int, 5) // len(a)=5
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
fmt.Println(a) // [0 0 0 0 0]を返す
sliceへの要素の追加(append)
append関数で要素の追加を行える。
引数は以下のとおり。
append(追加する対象, 追加する要素, 追加する要素, ...)
var s []int
s = append(s, 0, 1, 2, 3)
fmt.Println(s) // [0 1 2 3]を返す
sliceの要素にそれぞれアクセス(range)
range sliceという記述でsliceの要素にそれぞれアクセスできる。
range関数の戻り値はインデックスと要素の値であることに注意。
for文と組み合わせた例は以下のとおり。
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
/* 実行結果
2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
*/
インデックスや値を_に代入することで、それを使用しないことを明示する粋な表記もある。
for _, value := range pow {
fmt.Printf("%d\n", value)
}
map型
配列と似たmap型の定義等も残しておく。
pythonでいう辞書型と一緒でkeyとvalueという概念が存在する。
定義の仕方
map[keyの型]valueの型{key: value}で定義できる。
m := map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
fmt.Println(m["key1"]) // value1を返す
n := make(map[string]string) // make関数で定義する場合
要素の削除(delete)
delete関数で指定したkeyを削除できる。
引数はdelete(対象のmap、削除したいkey)とする。
引数を増やして複数のkeyを同時に削除することはできない。
m := map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
delete(m, "key1")
fmt.Println(m) // map[key2:value2 key3:value3]を返す
keyが存在するかどうかの確認
指定したkeyにvalueが存在するかどうかの確認は以下の記述で行える。
m := make(map[string]string)
value, ok := m["key1"] // 指定したkeyの値と、指定したkeyが存在するかどうかのbool値をそれぞれ代入
fmt.Println(value) // 0を返す
fmt.Println(ok) // falseを返す