Go初心者のためのメモ(ややこしい配列編)

#はじめに
go言語初心者のための記事です。
公式チュートリアルの大事なところをまとめただけです。
この記事では配列、および配列に似たものをまとめます。
array、slice、mapの3つです。

##ややこしいGoにおける配列の概念
Goには二つの配列表現arrayとsliceがある。
とてもややこしいが、公式チュートリアル曰く、

- 固定長がarray(=配列)
- 可変長がslice

という定義らしい。

###配列(array)
Goの配列(array)は必ず配列の長さを指定する。
`array[i:j]`という書き方で`i`から`j`前までの要素を取得できる。

```go
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と呼ぶこととする。

```go
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にも反映される。
日本語下手なので下記の例を見てください。

```go
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の次元を表現できる。


```go
slice := [][]string{
	[]string{"犬", "猫", "猿"},
	[]string{"りんご", "ばなな", "パイナップル"},
	[]string{"男", "女", "あいつ"},
}
fmt.Println(slice[1][2]) // パイナップルを返す
```

###sliceの長さと容量
sliceには長さ(length)と容量(capacity)という概念がある。
長さ(length)はどの言語にもよくある配列の長さのようなもの。
容量(capacity)は聞いたことなかったが考え方は簡単で、
`元のarrayの長さ - arrayから取得し始めたsliceの要素のインデックス`
ってだけ。
これも実行して確認するほうが理解が早い。

```go
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の容量のみ省略できる。

```go
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(追加する対象, 追加する要素, 追加する要素, ...)`

```go
var s []int
s = append(s, 0, 1, 2, 3)
fmt.Println(s) // [0 1 2 3]を返す
```

###sliceの要素にそれぞれアクセス(range)
`range slice`という記述でsliceの要素にそれぞれアクセスできる。
`range`関数の戻り値はインデックスと要素の値であることに注意。
for文と組み合わせた例は以下のとおり。

```go:main.go
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
*/
```

インデックスや値を`_`に代入することで、それを使用しないことを明示する粋な表記もある。

```go
for _, value := range pow {
	fmt.Printf("%d\n", value)
}
```

##map型
配列と似たmap型の定義等も残しておく。
pythonでいう辞書型と一緒でkeyとvalueという概念が存在する。
###定義の仕方
`map[keyの型]valueの型{key: value}`で定義できる。

```go
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を同時に削除することはできない。


```go
m := map[string]string{
    "key1": "value1",
    "key2": "value2",
    "key3": "value3",
}
delete(m, "key1")
fmt.Println(m) // map[key2:value2 key3:value3]を返す
```

###keyが存在するかどうかの確認
指定したkeyにvalueが存在するかどうかの確認は以下の記述で行える。

```go
m := make(map[string]string)
value, ok := m["key1"] // 指定したkeyの値と、指定したkeyが存在するかどうかのbool値をそれぞれ代入
fmt.Println(value) // 0を返す
fmt.Println(ok) // falseを返す
```