Go 基本文法【参照型編】

## はじめに
今回はGoの基本文法である<b>「参照型」</b>についてです。

## 目次
1. [参照型 Slices ： スライス(可変長配列)](#参照型-slices--スライス可変長配列)
2. [参照型 Maps ： マップ(連想配列)](#参照型-maps--マップ連想配列)
3. [参照型 Range ： レンジ(反復処理)](#参照型-range--レンジ反復処理)
4. [参考文献](#参考文献)

## 参照型 Slices ： スライス(可変長配列)
スライスは<b>可変長配列</b>を指します。
スライスの宣言方法は以下です。
配列(Arrays)と違い、スライスは [ ] の中に大きさを指定しません。
```
　① var 変数名 []型
　② var 変数名 []型 = []型{初期値1, ..., 初期値n} 
　③ 変数名 := 配列[start:end] 
　 　⇨ 配列(またはスライス)のstartから(end - 1)を取り出す事でスライスを生成
　④ 変数名 := 配列[len(要素数):end] ⇨ startをlen(要素数)で指定
　⑤ make で要素数を決めた後、一部の要素へデータを格納
```
```golang:main.go
package main

import "fmt"

func main() {
	// ①
	var s1 []string
	fmt.Println(s1) // => []

	// ②
	s2 := []int{1, 2, 3, 4, 5}
	fmt.Println(s2) // => "[1 2 3 4 5]"

	// ③
	s3 := s2[0:3]
	fmt.Println(s3) // => "[1 2 3]"

	// ④
	s4 := s2[len(s2)-2 : 5]
	fmt.Println(s4) // => "[4 5]"

	// ⑤
	s5 := make([]int, 5)
	s5[0] = 3
	fmt.Println(s5) // => "[3, 0, 0, 0, 0]"
}
```
```[start:end]```の指定パターンは以下のとおりです。
| パターン | 意味 |
|:--|:--|
| Slice[start:end] | start から end - 1 まで |
| Slice[start:] | start から最後尾まで |
| Slice[:end] | 先頭から end - 1 まで |
| Slice[:] | 先頭から最後尾まで |

ちなみに、<b>スライスとスライス元となった配列の要素は共有</b>されます。
なので、スライスの要素を変更すると<b>スライス元の配列要素に対しても変更がかかリます</b>。
```golang:main.go
func main() {
	slice_target := [...]string{"Hello", "Go"}
	slice := slice_target[0:2] // スライスの生成

	slice[1] = "PHP" // slice[1]の要素を変更
	fmt.Println(slice_target) // => [Hello PHP] // slice_target の要素も変更されている
}
```
<b>スライスへの要素追加</b>は組み込み関数```append()```を使用することで可能です。
```golang
new_slice = append(slice, 追加要素)
```
```golang:main.go
func main() {
	slice_target := []string{"Hello", "Go"}
	new_slice := append(slice_target, "PHP") // slice_target に "PHP" を追加

	fmt.Println(new_slice)    // => [Hello Go PHP]
	fmt.Println(slice_target) // => [Hello Go] // 元の値は変わっていない。
}
```
ここで、スライスで使われる```length(長さ)```と```capacity(容量)```について解説です。
　・```length``` ： length を指定したスライスの要素数
　・```capacity``` ： capacity を指定したスライスの生成元の要素数
　length と capacity は```len()```と```cap()```という式を使います。
```golang:main.go
func main() {
	slice_target := [...]string{"Hello", "Go"}
	s1 := slice_target[0:1]

	fmt.Println(s1)      // => Hello
	fmt.Println(len(s1)) // => 1 // s1 の要素数は１つなので1を返す。
	fmt.Println(cap(s1)) // => 2 // s1 の生成元の要素数は２つなので2を返す。
}
```
また、スライスには<b>完全スライス型</b>というものがあります。
```low```、```high```、```max```の3つのパラメータを使ってスライスを生成します。
```golang
slice[low:high:max]
// この時のlenとcapは各々以下で算出される
// len() ： high - low
// cap() ： max - low
```
```golang:main.go
func main() {
	slice_targat := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	s1 := slice_targat[2:4:4] // == "[3, 4]"
	fmt.Println(len(s1))      // == 2
	fmt.Println(cap(s1))      // == 2

	s2 := slice_targat[2:4:6] // == "[3, 4]"
	fmt.Println(len(s2))      // == 2
	fmt.Println(cap(s2))      // == 4
}
```
スライスは<b>型が一致している場合</b>、他のスライスへ代入することができます。
```golang:main.go
func main() {
	slice_target := []string{"Hello", "Go"}
	var s1 []string // slice_target と同型である s1 を作成

	s1 = slice_target // slice_target を s1 へ代入

	fmt.Println(s1) // => [Hello Go]
}
```
スライスの<b>ゼロ値</b>は```nil```です。
```nil```スライスは、0 の length と capacity を持っており、元となる配列は持っていません。
```golang:main.go
func main() {
	var slice_target []int
	fmt.Println(slice_target, len(slice_target), cap(slice_target)) // => [] 0 0

	// 条件式では nil と比較
	if slice_target == nil {
		fmt.Println("nil!") // => nil!
		// slice_target の値が nil の場合に nil! を表示
	}
}
```
スライスは組み込み関数の```make()```を使って定義することもできます。
```golang
make([]型, len, cap)
```
```golang:main.go
func main() {
	slice := make([]int, 3, 3) // スライス生成
	slice[1] = 1 // => slice[1] へ1を代入
	fmt.Println(slice) // => [0 0 0]
}
```

## 参照型 Maps ： マップ(連想配列)
マップは<b>連想配列</b>を指します。要素と値がセットになっています。
マップの生成方法は以下の通りです。
```golang
var マップ名 map[要素の型]値の型
マップ名 := make(map[要素の型]値の型)
```
色々と書いてみました。特徴・記法については以下の通りです。
```golang:main.go
package main

import "fmt"

func main() {
	// マップ生成 ： ※出力値は五十音順にソートされる
	m := map[string]int{"japan": 100, "usa": 200, "canada": 300}
	fmt.Println(m) // => map[canada:300 japan:100 usa:200]

	// 空のマップ生成、値を代入
	m2 := make(map[string]int)
	m2["apple"] = 1
	fmt.Println(m2) // => map[apple:1]

	// 値の参照
	fmt.Println(m["japan"]) // => 100

	// 値の追加・更新
	m["italy"] = 500
	fmt.Println(m) // => map[canada:300 italy:500 japan:100 usa:200]
	m["japan"] = 150
	fmt.Println(m) // => map[canada:300 italy:500 japan:150 usa:200]

	// 値の存在チェック
	v1, check := m["korean"]
	fmt.Println(v1, check) // => 0 false

	v2, check := m["japan"]
	fmt.Println(v2, check) // => 100 true

	// 値の消去
	delete(m, "italy")
	fmt.Println(m) // => map[canada:300 japan:150 usa:200]

	// マップから要素のみを抽出
	fmt.Println(extract_keys(m)) // => [japan usa canada]

	// マップから値のみを抽出
	fmt.Println(extract_values(m)) // => [150 200 300]

	// マップを多次元配列へ変換
	fmt.Println(convert_ma(m)) // => [[japan 150] [usa 200] [canada 300]]

	// 特定要素の値のみを抽出
	keys := []string{"usa", "canada"}
	fmt.Println(extract_pinpoint_values(m, keys)) // => [200 300]

	// マップ同士をマージ(結合)
	merge1 := map[string]string{"key1": "val1", "key2": "val2"}
	merge2 := map[string]string{"key3": "val3"}
	fmt.Println(merge(merge1, merge2)) // => map[key1:val1 key2:val2 key3:val3]
}

// マップから要素のみを抽出
func extract_keys(m map[string]int) []string {
	ks := []string{}
	for k, _ := range m {
		ks = append(ks, k)
	}
	return ks
}

// マップから値のみを抽出
func extract_values(m map[string]int) []int {
	vs := []int{}
	for _, v := range m {
		vs = append(vs, v)
	}
	return vs
}

// マップを多次元配列へ変換
func convert_ma(m map[string]int) []interface{} {
	a := []interface{}{}
	for k, v := range m {
		a = append(a, []interface{}{k, v})
	}
	return a
}

// 特定要素の値のみを抽出
func extract_pinpoint_values(m map[string]int, keys []string) []int {
	vs := []int{}
	for _, k := range keys {
		vs = append(vs, m[k])
	}
	return vs
}

// マップ同士をマージ(結合)
func merge(m1, m2 map[string]string) map[string]string {
	ans := map[string]string{}

	for k, v := range m1 {
		ans[k] = v
	}
	for k, v := range m2 {
		ans[k] = v
	}
	return (ans)
}
```

## 参照型 Range ： レンジ(反復処理)
for ループに利用する range は、スライスやマップを反復処理するために使います。
range の生成方法は以下の通りです。
```golang
for 要素, 値 := range スライスまたはマップ名 {}
```

for と range の扱い方は主に3種類です。
```
　①要素と値を取り出す
　②要素だけを取り出す(値を```_```で出力しないようにする)
　③値だけを取り出す(要素を```_```で出力しないようにする)
```
以下はスライスを for と range で取り出しています。
```golang:main.go
package main

import "fmt"

func main() {
    // ①
    var country = []string{"japan", "usa", "canada", "italy"}
	for index, value := range country {
		fmt.Println(index, value) // => 0 japan 1 usa 2 canada 3 italy
	}

    // ②
	var country = []string{"japan", "usa", "canada", "italy"}
	for index, _  := range country {
		fmt.Println(index) // => 0 1 2 3
	}

    // ③
	var country = []string{"japan", "usa", "canada", "italy"}
	for _, value := range country {
		fmt.Println(value) // => japan usa canada italy
	}
}
```
```_```は省略可能です。
```golang
for index := range country
```
マップは以下のように取り出します。
```golang:main.go
func main() {
	m := map[string]int{"japan":100, "usa":200, "canada": 300}
	for index, value := range m {
		fmt.Println(index, value) // => japan 100 usa 200 canada 300
	}
}
```

## 参考文献
<a href="https://go-tour-jp.appspot.com/">A Tour of Go</a>
<a href="https://golang.hateblo.jp/entry/golang-slice-array">Go言語(golang) スライスと配列の使い方</a>
<a href="https://ashitani.jp/golangtips/tips_map.html#map_Map">逆引きGolang (マップ)</a>
<a href="https://golang.keicode.com/basics/go-map.php">Go 言語のマップ (map)</a>
<a href="https://y-hiroyuki.xyz/go/infinite-processing/for-range#sec1">【Go入門】forとrangeを使った取り出し方について</a>