【Go】基本文法メモ④(配列・スライス)

# 概要
[A Tour of Go](https://tour.golang.org/)の順番に沿ってGoの基本で個人的に学習したことをまとめています。


| No | 記事 |
|------|---------|
|    1  |   [【Go】基本文法①(基礎)](https://qiita.com/k-penguin-sato/items/1d0e1c6b4bf937996cd3)|
|    2  |   [【Go】基本文法②(フロー制御文)](https://qiita.com/k-penguin-sato/items/31b45fd3914797b654f0)|
|    3  |  [【Go】基本文法③(ポインタ・構造体)](https://qiita.com/k-penguin-sato/items/62dfe0f93f56e4bf9157)|
|    4  |  __〜〜【Go】基本文法④(配列・スライス)「今ココ」〜〜__|
|    5  |   [【Go】基本文法⑤(Maps・ Range)](https://qiita.com/k-penguin-sato/items/a320072fa09502bde3e9)|
|    6  |    [【Go】基本文法⑥(インターフェース)](https://qiita.com/k-penguin-sato/items/885a61d819cc431304f5)     |
|    7  |     [【Go】基本文法⑦(並行処理)](https://qiita.com/k-penguin-sato/items/5b09fa89d8d231bcdac8)    |
|    8  |    [【Go】基本文法総まとめ](https://qiita.com/k-penguin-sato/items/deaeab18aa416496e273)     |


今回は `Arrays(配列)` と `slices(スライス)` に焦点を当てて学習しました。

# Arrays(配列)
配列とは、同じ型を持つ値（要素）を並べたものです。
Goの `Arrays(配列)` は固定長の的な配列なので最初に宣言した配列のサイズを変えることはできません。

### 配列の宣言方法
Goでは配列を以下の様に宣言します。

```
① var 変数名 [長さ]型
② var 変数名 [長さ]型 = [大きさ]型{初期値1, 初期値n} 
③ 変数名 := [...]型{初期値１, 初期値n}
```

①の方法で配列を宣言した例

```Golang
func main(){
   var arr [2]string
       arr[0] = "Golange"
       arr[1] = "Java"
       fmt.Println(arr[0], arr[1]) //=> Golange Java
       fmt.Println(arr) //=> [Golange Java]
}
```

②の方法で配列を宣言した例

```Golang
func main(){
   var arr [2]string = [2]string {"Golang", "Java"}
       fmt.Println(arr[0], arr[1]) //=> Golange Java
       fmt.Println(arr) //=> [Golange Java]
}
```

③の方法で配列を宣言した例
この宣言方法では要素数は省略が可能です。
しかし、後ろに書いた要素の数を自動でカウントしてくれているだけで、要素数を明記した場合と実態に違いはありません。

```Golang
func main(){
     arr := [...] string{"Golang", "Java"}
     fmt.Println(arr[0], arr[1]) //=> Golange Java
     fmt.Println(arr) //=> [Golange Java]
}
```
# Slices(スライス)
Goの `Arrays(配列)`は固定長の様な配列である一方、Goの `Slices(スライス)` は可変長の配列の様な動きをするのでより柔軟にデータ（要素）を格納することが可能です。

### スライスの宣言方法
Goではスライスを以下の様に宣言します。
配列の宣言と違って、スライスは `[ ]` の中に大きさを指定しません。
また、スライスは配列への_「参照型」_で値を持つため、配列から部分列を取り出す事 `（スライス操作）` でも作成する事が可能です。

```
① var 変数名 []型
② var 変数名 []型 = []型{初期値1, ..., 初期値n} 
③ 変数名 := 配列[start:end] 
//配列(またはスライス)のstartから(end - 1)を取り出す事でスライスを作成する。 
```

①の方法で宣言した例

```Golang
func main(){
     var slice []string
     fmt.Println(slice) //=> []
}
```

②の方法で宣言した例

```Golang
func main(){
     slice := [] string{"Golang", "Java"}
     fmt.Println(slice) //=> [Golange Java]
}
```

③の方法で宣言した例

```Golang
func main(){
     arr := [...] string{"Golang", "Java"}
	 slice := arr[0:2]
     fmt.Println(slice) //=> [Golange Java]
}
```
__スライス操作には以下の様なものがあります。__
上記の例では `Slice[start:end]` の例を使用しています。

| 操作 | 意味 |
|:--|:--|
| Slice[start:end] | start から end - 1 まで |
| Slice[start:] | start から最後尾まで |
| Slice[:end] | 先頭から end - 1 まで |
| Slice[:] | 先頭から最後尾まで |

__スライス操作を行う場合は生成元の配列（またはスライス）と要素を共有します。__
__つまり、スライスの要素を変更すると、その元となる配列の対応する要素が変更されます。__

```Golang 
func main(){
     arr := [...] string{"Golang", "Java"}
     slice := arr[0:2] //スライスの作成
     
     slice[0] = "Ruby" //slice[0]の要素を変更
     fmt.Println(arr) //=> [Ruby Java] //arrの要素も変更されている事を確認
}
```

### 要素の追加
Goでは配列は宣言時に要素の数が固定されるので要素の追加はできません。
スライスに要素を追加したい場合は組み込み関数 `append()` を使用する事で簡単に行えます。
__(append は新しいスライスを返すことに注意してください。)__

以下の様に書く事で元の配列（スライス）の末尾に指定した要素を追加した値を返します。

```Golang
newSlice = append(slice, 追加要素)
```

```Golang
func main(){
     slice := [] string{"Golang", "Java"}
     newSlice := append(slice, "Ruby") //sliceに"Ruby"を追加

     fmt.Println(newSlice) //=> [Golang Java Ruby]
     fmt.Println(slice) //=> [Golang Java] //元の値は変わっていない。
}
```

### スライスの長さ(length)と容量(capacity)
スライスは `長さ( length )` と `容量( capacity )` の両方を持っています。

-  `長さ(length)` は、それに含まれる要素の数です。
- `容量(capacity)` は、スライスの最初の要素から数えて、元となる配列の要素数です。

スライスの長さと容量は `len()` と `cap()` という式を使用して得ることができます。

```Golang
func main(){
    arr := [...] string{"Golang", "Java"}
    slice := arr[0:1]
    
    fmt.Println(slice) //=> Golang　
    fmt.Println(len(slice)) //=> 1 //sliceの要素数は１つなので1を返す。
    fmt.Println(cap(slice)) //=> 2 //sliceの生成元の要素数は２つなので2を返す。
}
```
### スライスの代入
スライスの型が一致している場合、スライスを代入することができます。

```Golang
func main(){
     slice := [] string{"Golang", "Java"}
 var slice2 []string //sliceと同型slice2を作成
	 
     slice2 = slice //sliceをslice2に代入
	 
     fmt.Println(slice2) //=> [Golange Java]
}
```
`slice` からも `slice2` の配列本体にアクセスすることができます。
また、`slice[0]` の値を書き換えると、`slice2` の値も変化します。

```Golang
func main(){
     slice := [] string{"Golang", "Java"}
 var slice2 []string //sliceと同型slice2を作成
	 
     slice2 = slice //sliceをslice2に代入
     slice2[0] = "Ruby" //slice2[0]の値を変更
	 
     fmt.Println(slice2) //=> [Ruby Java] 
     fmt.Println(slice) //=> [Ruby Java] //slice2での変更によりsliceの要素も変更されている。
}
```

### スライスのゼロ値
スライスのゼロ値は `nil` です。
`nil` スライスは 0 の長さと容量を持っており、何の元となる配列も持っていません。

```Golang 
func main() {
	var slice []int
	fmt.Println(slice, len(slice), cap(slice)) //=> [] 0 0
	
	if slice == nil {
		fmt.Println("nil!") //=> nil! 
		//sliceの値がnilの場合にnil!を表示する。
	}
}
```
### 組み込み関数`make()`でスライスを作成する
スライスは組み込み関数の `make()` を利用する事で定義することもできます。

```Golang 
make([]T, len, cap)
```
上記の`make()` 関数の第 1 引数 `[]T` が型、第 2 引数 (`len`) が 長さ 、第 3 引数 (`cap`) が 容量 を意味しています。

```Golang 
func main() {
     a := make([]int,5, 5)
     fmt.Println(a) //=> [0 0 0 0 0]
}
```

# 参考
[My Journey of Go④](https://k-blog0130.herokuapp.com/posts/17)
[お気楽 Go 言語プログラミング入門](http://www.geocities.jp/m_hiroi/golang/abcgo02.html)
[Goの基本 | array と slice の違い](https://qiita.com/YumaInaura/items/aec7857518102ff5e27c)
[はじめてのGo言語（スライス１）](http://cuto.unirita.co.jp/gostudy/post/go_slice/)