【A Tour of Go】基本編③ 〜構造体、配列、スライス、マップ〜

公式の [A Tour of Go](https://go-tour-jp.appspot.com/list) ではじめて Go 言語を触ってみました。
以下、構造体、配列、スライス、マップについて学んだことのメモ。

前回の記事はこちら

https://qiita.com/BitterBamboo/items/58d80a1a1a85e18188ce

https://qiita.com/BitterBamboo/items/f72ce6f7ce20e6b5f6c7

## ポインタ

* ポインタは値のメモリアドレスを指す
* 変数`T`のポインタは`*T`型で、ゼロ値は`nil`

``` go
var p *int
```

* `&`演算子は、そのオペランドへのポインタを引き出す

``` go
i := 42
p = &i
```

* `*`演算子は、ポインタの指す先の変数を示す（*間接参照*）

``` go
fmt.Println(*p)
*p = 21 // ポインタ p を介して i へ値を代入する
```

## 構造体

### 構造体とは

* 構造体（`struct`）は、フィールドの集まり

``` go
package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	fmt.Println(Vertex{1, 2}) // {1 2}
}
```

### フィールドへのアクセス

* 構造体のフィールドは、ドット`.`を用いてアクセスする

``` go
package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	v.X = 4
	fmt.Println(v.X) // 4
}
```

* 構造体のフィールドは、構造体のポインタを通してアクセスすることができる
	* フィールド`X`を持つ struct のポインタ`p`
	* フィールド`X`を間接参照するには`(*p).X`
	* しかしこの表記は面倒なので、Goでは代わりに`p.X`と書ける

``` go
package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	p := &v  // ポインタ
	p.X = 1e9 // Xへの間接参照 (*p).X
	fmt.Println(v) // {1000000000 2}
}
```


### 構造体リテラル

* 構造体を初期化する方法
	* フィールドの初期値を`{}`内に列挙
	* `{Name: }`構文を使う

``` go
package main

import "fmt"

type Vertex struct {
	X, Y int
}

var (
	v1 = Vertex{1, 2} // has type Vertex
	v2 = Vertex{X: 1} // Y:0 is implicit
	v3 = Vertex{}     // X:0 and Y:0
	p = &Vertex{1, 2} // has type *Vertex

func main() {
	fmt.Println(v1, p, v2, v3)
}
```


## 配列

### 配列とは

* `[n]T`型は、型`T`の`n`個の変数の配列を表す
* 固定長

``` go
package main

import "fmt"

func main() {
	var a [2]string
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])
	fmt.Println(a)

	primes := [6]int{2, 3, 5, 7, 11, 13}
	fmt.Println(primes)
}
```


## スライス

### スライスとは

* 型`[]T`は型`T`のスライスを表す
* 可変長
* より柔軟な配列と見なすことができる
* 配列からスライスを抜き出す方法
	* `a[low:high]`
	* `low`を含むが`high`は含まない（右半開区間）
	* `a`の要素のうち1から3を含むスライスを作る例: `a[1:4]`

``` go
package main

import "fmt"

func main() {
	primes := [6]int{2, 3, 5, 7, 11, 13}

	var s []int = primes[1:4]
	fmt.Println(s)
}
```

* スライスは配列への参照のようなもの
	* スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示している
	* スライスの要素を変更すると、その元のなる配列の対応する要素が変更される

``` go
package main

import "fmt"

func main() {
	names := [4]string{
		"John",
		"Paul",
		"George",
		"Ringo",
	}
	fmt.Println(names)

	a := names[0:2] // [John Paul]
	b := names[1:3] // [Paul George]
	fmt.Println(a, b)

	b[0] = "XXX"
	fmt.Println(a, b)
	fmt.Println(names)
}
```


### スライスリテラル

* 長さのない配列リテラルのようなもの
* `[]bool{true, true, false}`
	* まず配列 `[3]bool{true, true, false}`を作成
	* 次にこの配列を参照するスライスを作成


``` go
package main

import "fmt"

func main() {
	q := []int{2, 3, 5, 7, 11, 13}
	fmt.Println(q)

	r := []bool{true, false, true, true, false, true}
	fmt.Println(r)

	s := []struct { // 構造体のスライスリテラル
		i int
		b bool
	}{
		{2, true},
		{3, false},
		{5, true},
		{7, true},
		{11, false},
		{13, true},
	}
	fmt.Println(s)
}
```


### スライスの既定値

* 配列`var a [10]int`において以下のスライスは全て等価
	* `a[0:10]`
	* `a[:10]`
	* `a[0:]`
	* `a[:]`

``` go
package main

import "fmt"

func main() {
	s := []int{2, 3, 5, 7, 11, 13}

	s = s[1:4] // [3 5 7]
	fmt.Println(s)

	s = s[:2] // [3 5]
	fmt.Println(s)

	s = s[1:] // [5]
	fmt.Println(s)
}
```


### スライスの長さと容量

* 長さ: スライスに含まれる要素の数
	* `len(s)`で取得
* 容量: スライスの最初の要素から数えた元の配列の要素数
	* `cap(s)`で取得

``` go
package main

import "fmt"

func main() {
	s := []int{2, 3, 5, 7, 11, 13}
	printSlice(s) // len=6 cap=6 [2 3 5 7 11 13]

	// Slice the slice to give it zero length.
	s = s[:0]
	printSlice(s) // len=0 cap=6 []

	// Extend its length.
	s = s[:4]
	printSlice(s) // len=4 cap=6 [2 3 5 7]

	// Drop its first two values.
	s = s[2:]
	printSlice(s) // len=2 cap=4 [5 7]

	// Extend its length more than the capacity
	s = [:5]
	printSlice(s) // error: slice bounds out of range [:5] with capacity 4
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
```


### スライスのゼロ値

* スライスのゼロ値は`nil`
* 0の長さ、0の容量、元の配列を持たない


### `make`関数によるスライスの生成

* `make`関数はゼロ化された配列を用意し、その配列を指すスライスを返す
* 2番目の引数は長さ、3番目の引数は容量

``` go
package main

import "fmt"

func main() {
	a := make([]int, 5)
	printSlice("a", a) // len=5 cap=5 [0 0 0 0 0]

	b := make([]int, 0, 5)
	printSlice("b", b) // len=0 cap=5 []

	c := b[:2]
	printSlice("c", c) // len=2 cap=5 [0 0]

	d := c[2:5]
	printSlice("d", d) // len=3 cap=3 [0 0 0]
}

func printSlice(s string, x []int) {
	fmt.Printf("%s len=%d cap=%d %v\n",
		s, len(x), cap(x), x)
}
```


### スライスのスライス

``` go
package main

import (
	"fmt"
	"strings"
)

func main() {
	// Create a tic-tac-toe board.
	board := [][]string{ // スライスリテラル、ただし[][]
		[]string{"_", "_", "_"}, // スライスリテラル
		[]string{"_", "_", "_"}, // スライスリテラル
		[]string{"_", "_", "_"}, // スライスリテラル
	}

	// The players take turns.
	board[0][0] = "X"
	board[2][2] = "O"
	board[1][2] = "X"
	board[1][0] = "O"
	board[0][2] = "X"

	for i := 0; i < len(board); i++ {
		fmt.Printf("%s\n", strings.Join(board[i], " "))
	}
}
```


### スライスへの要素の追加

* スライスへ新しい要素を追加するには、組み込みの`append`関数を使う
* `append`の戻り値はスライス
* 元の配列の容量が小さい場合は、より大きな容量の配列を割り当て直す
	* 戻り値となるスライスは、新しい割当先を示すようになる

``` go
package main

import "fmt"

func main() {
	var s []int
	printSlice(s) // len=0 cap=0 []

	// append works on nil slices.
	s = append(s, 0)
	printSlice(s) // len=1 cap=1 [0]

	// The slice grows as needed.
	s = append(s, 1)
	printSlice(s) // len=2 cap=2 [0]

	// We can add more than one element at a time.
	s = append(s, 2, 3, 4)
	printSlice(s) // len=5 cap=6 [0 1 2 3 4]
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
```


## Range

* `for`ループに利用する`range`は、スライスやマップをひとつずつ反復処理するために使う
* スライスを`range`で繰り返す場合、`range`は反復ごとに2つの変数を返す
	* 1つ目の変数: インデックス
	* 2つ目の変数: インデックスの場所の要素のコピー

``` go
package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}
```

* インデックスや値は`_`へ代入することで捨てることができる

``` go
for i, _ := range pow
for _, value := range pow

// インデックスだけ必要なのであれば
for i := range pow
```


## マップ

### マップ（連想配列）とは

* `map`はキーと値とを関連づける
* ゼロ値は`nil`
	* `nil`マップはキーを持っておらず、またキーを追加することもできない
* `make`関数は指定された型のマップを初期化して、使用可能な状態で返す

``` go
package main

import "fmt"

type Vertex struct {
	Lat, Long float64
}

var m map[string]Vertex
// var で宣言しただけの時点でキーを追加しようとすると
// panic: assignment to entry in nil map

func main() {
	m = make(map[string]Vertex)
	m["Bell Labs"] = Vertex{
		40.68433, -74.39967,
	}
	fmt.Println(m["Bell Labs"]) // {40.68433 -74.39967}
}
```


### マップリテラル

* 構造体リテラルに似ているが、キーが必要

``` go
package main

import "fmt"

type Vertex struct {
	Lat, Long float64
}

var m = map[string]Vertex{
	"Bell Labs": Vertex{
		40.68433, -74.39967,
	},
	"Google": Vertex{
		37.42202, -122.08408,
	},
}

func main() {
	fmt.Println(m) // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
}
```

* もし`map`に渡すトップレベルの型が単純な型名である場合は、リテラルの要素から推定できるので、その型名を省略することができる

``` go
var m = map[string]Vertex{
	"Bell Labs": {40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
}
```


### マップの操作

* map`m`への操作
	* 要素の挿入や更新: `m[key] = elem`
	* 要素の取得: `elem = m[key]`
	* 要素の削除: `delete(m, key)`
	* キーに対する要素が存在するかどうかは2つ目の戻り値で確認: `elem, ok = m[key]`
		* `m`に`key`がある =>  `ok` は true
		* `m`に`key`がない =>  `ok`は false
			* このとき`elem`はmapの要素の型のゼロ値となる

``` go
package main

import "fmt"

func main() {
	m := make(map[string]int)

	m["Answer"] = 42
	fmt.Println("The value:", m["Answer"]) // 42

	m["Answer"] = 48
	fmt.Println("The value:", m["Answer"]) // 48

	delete(m, "Answer")
	fmt.Println("The value:", m["Answer"]) // 0

	v, ok := m["Answer"]
	fmt.Println("The value:", v, "Present?", ok) // 0 false
}
```

## 関数

### 関数値

* Goの関数は変数である
* 引数や戻り値にとることができる

``` go
package main

import (
	  "fmt"
	  "math"
)

func compute(fn func(float64, float64) float64) float64 {
	// fn: 関数の引数に「関数値」をとることができる
	// fn の引数: float64, float64
	// fn の戻り値: float64
	return fn(3, 4) // 関数値は戻り値としても利用可能
}

func main() {
	hypot := func(x, y float64) float64 {
		return math.Sqrt(x*x + y*y)
	} // 関数も変数である（関数値）
	fmt.Println(hypot(5, 12))

	fmt.Println(compute(hypot)) // 関数 compute に関数を渡している
	fmt.Println(compute(math.Pow))
}
```


### クロージャ

* Goの関数はクロージャである
	* 外部から変数を参照する関数値
		* クロージャは変数へ *bind* されている
	* 参照された変数にアクセスして変えることができる


``` go
package main

import "fmt"

func adder() func(int) int {
	sum := 0 // クロージャに参照されている変数
	return func(x int) int {
		sum += x
		return sum
	} // 変数 sum に bind されたクロージャを返している
}

func main() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
		// 0 0
		// 1 -2
 		// 3 -6
 		// 6 -12
 		// 10 -20
	}
}
```

# 次回

https://qiita.com/BitterBamboo/items/1fbd9ff6d0ec8d064062