Goのarrayとsliceとmapを理解する #golang

## array 
### 長さがポイント

* 固定長配列
* 初期値は0

**書き方**
` [長さ]型{値}`

```
    var a1 [5]int            // array型の変数を宣言するとき(初期値0が入る)
    var a2 = [5]int{1, 2, 3} // 配列を作って初期値を指定するとき
    a3 := [5]int{1, 2, 3}    // 代入演算子を使って簡易表記するとき
    a4 := [...]int{1, 2, 3}  // 長さを省略するとき

    fmt.Println(a1, len(a1)) // [0 0 0 0 0] 5
    fmt.Println(a2, len(a2)) // [1 2 3 0 0] 5
    fmt.Println(a3, len(a3)) // [1 2 3 0 0] 5
    fmt.Println(a4, len(a4)) // [1 2 3] 3



    a1[2] = 5 // 値を変更するとき
    fmt.Println(a1) // [0 0 5 0 0]
```

## slice 
### ポインタと容量がポイント

* 可変長配列のようなもの
* 初期値はnil

arrayと比較して以下の違いがある。

* 実体(array)とポインタの両方を持っている
    * ポインタ: エイリアスのようなもので、アドレスとも呼ばれる
* 容量(cap)を持っている
    * 長さ < 容量 < 参照元の容量　の範囲内で指定できる
    * スライスをスライスするときは[]の三番目に指定できる

**書き方**
`[]型{値}`

```
    var s1 []int               // slice型の変数を宣言するとき(初期値nilが入る)
    var s2 = []int{1, 2, 3, 4} // 値を指定するとき
    s3 := []int{1, 2, 3, 4}    // 代入演算子を使って簡易表記するとき

    fmt.Println(s1, len(s1), cap(s1)) // [] 0 0
    fmt.Println(s2, len(s2), cap(s2)) // [1 2 3 4] 4 4
    fmt.Println(s3, len(s3), cap(s3)) // [1 2 3 4] 4 4



    s3s := s3[0:2]                       // sliceをsliceするとき
    fmt.Println(s3s, len(s3s), cap(s3s)) // [1 2] 2 4(容量を指定しないと参照元を引き継ぐ)



    s3sc := s3[0:2:3]                       // 容量を指定してsliceをsliceするとき
    fmt.Println(s3sc, len(s3sc), cap(s3sc)) // [1 2] 2 3
```

### :star:組み込み関数make()を使う場合

* 長さと容量を指定し、sliceをつくる
* 長さは省略できないが、容量は省略できる
* 容量を省略すると、要素数=容量となる
* 初期値は0
* make関数はスライスを初期化する。初期値としてnilではなく0を格納する

`書き方 : make(型, 要素数, 容量)`

```
    var sm1 = make([]int, 5)      // 容量を省略してsliceをつくるとき(初期値0が入る)
    var sm2 = make([]int, 5, 10)  // 容量を指定してsliceをつくるとき
    sm3 := make([]int, 5, 10)     // 代入演算子を使って簡易表記するとき

    fmt.Println(sm1, len(sm1), cap(sm1)) // [0 0 0 0 0] 5 5
    fmt.Println(sm2, len(sm2), cap(sm2)) // [0 0 0 0 0] 5 10
    fmt.Println(sm3, len(sm3), cap(sm3)) // [0 0 0 0 0] 5 10
```

:warning: 組み込み関数make()は参照型にしか使えない。(slice, map, channel)

## map 
### キーがポイント

* 連想配列のようなもの(辞書・ハッシュetc.)
* 初期値は nil
 
arrayやsliceと比較して以下の違いがある。

* 実体(array)を持っていない
* 組み込み関数cap()は使えない

**書き方**
`map[キー]型`

```
    var m1 map[int]string    // map型の変数を宣言するとき(初期値0が入る)

    var m2 = map[string]int{ // 値を指定するとき
        "dora": 0,
        "nobi": 1,
    }

    m3 := map[string]int{    // 代入演算子を使って簡易表記するとき
        "shizu":   0,
        "jai": 1,
        "sune":   2,
    }

    fmt.Println(m1, len(m1)) // map[] 0
    fmt.Println(m2, len(m2)) // map[dora:0 nobi:1] 2
    fmt.Println(m3, len(m3)) // map[shizu:0 jai:1 sune:2] 3




    m3["deki"] = 3 // 要素を追加するとき
    // m3[1:"dora"]
    fmt.Println(m3, len(m3)) // map[shizu:0 jai:1 sune:2 deki:3] 4

    m3["shizu"] = 100        // キーをもとに値を書き換えるとき
    fmt.Println(m3, len(m3)) // map[shizu:100 jai:1 sune:2 deki:3] 4
```

### :star:組み込み関数make()を使う場合

* 容量を指定し、mapをつくる
* 容量は省略できる
* 初期値は0

**書き方**
`make(map[キーの型]要素型, 容量)`

```
    var mm1 = make(map[int]int)       // 容量を省略してmapをつくるとき(初期値0が入る)
    var mm2 = make(map[int]string, 5) // 容量を指定してmapをつくるとき
    mm3 := make(map[int]int, 5)       // 代入演算子を使って簡易表記するとき

    fmt.Println(mm1, len(mm1)) // map[] 0
    fmt.Println(mm2, len(mm2)) // map[] 0
    fmt.Println(mm3, len(mm3)) // map[] 0



    var mm4 = make(map[string]string, 4) // 値を指定するとき(makeを使う場合、代入する形になる)
    mm4["鳥"] = "bird"
    mm4["木"] = "tree"

    fmt.Println(mm4, len(mm4)) // map[鳥:bird 木:tree] 2
```

参考:
[Go言語: いろいろなマップの作り方まとめ-Qiita](http://qiita.com/suin/items/7225ab9f2aeb6f55c606)

## Tips

* Goでは初期値を「ゼロ値」と呼ぶ
* 「型」と「リテラル」は別物

```
ex) var a int = 0x0719BEEFの場合

型: int
リテラル: 10x0719BEEF(値)を指す場合とvar a int = 0x0719BEEF(表記そのもの)を指す場合がある
```

<b> 組み込み関数make()とnew()の違い </b>


* make()は実体(array)をつくる。実体を返す。もともと実体を持っていない参照型にのみ使える。
* new()はメモリを割り当てるだけで、実体はつくらない。ポインタを返す。一般的に構造体型のメモリ割り当てにおいて使われる