Goを50時間勉強して分かったこと


Goを50時間ほど勉強して分かったことを整理します。

勉強時間の内訳は、

* Udemyの「[Go: The Complete Developer's Guide (Golang) -  Stephen Grider](https://www.udemy.com/go-the-complete-developers-guide/)」を全て完了（16時間）
* Udemyの「[Web Development w/ Google’s Go (golang) Programming Language - Todd McLeod](https://www.udemy.com/go-programming-language/)」を3/4ぐらい完了（16時間）
* 「[Go by Example - Mark McGranaghan](https://oohira.github.io/gobyexample-jp/)（無料）」 をざっと読む（2時間）
* 実際に自分でコードを書いてみた → コードは[こちら](https://github.com/kei178/go-mongo-api)（16時間）

です。

学習開始時のレベルは、Goを触るのは初めてで、Ruby や JavaScript は普通に書ける、といった感じでした。

# .goファイルと基本コマンド

Go の型や文法に触れる前に、.goファイルとその基本コマンドについて整理します。

## .goファイル

.goファイルのシンプルなコード例は次のとおりです。

```go:main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello, playground")
}
```

この例の処理結果は、[Go Playground](https://play.golang.org/) で確認できます（引用元）。

### package

`package` は「ワークスペース名」のようなもので、**実行可能**パッケージと**再利用**パッケージの２つがあります。実行可能パッケージは、必ず `main` と命名します。

|名前 |種類 |
|:---|:---|
|main|実行可能（executable） | 
| その他|再利用（reuseable） |

### import

`import` で標準ライブラリや外部ライブラリなど、必要な依存ファイルをインポートします。

### func main()

`func main()` は、`package main` ファイルの実行時に呼び出される関数です。`package main` では、必ず定義しないといけません。

## Go CLI

Go の基本的なコマンドラインは次のとおりです。

### go run

goファイルをコンパイルして処理を実行します。

```
$ go run main.go
```

冒頭のコード例を実行すると、次のとおり。

```
Hello, playground
```

### go build

goファイルをコンパイルして、実行可能な状態にします。

```
$ go build main.go
```

コンパイルされた `main` ファイルの実行。

```
$ ./main
```

### go get

外部ライブラリのインストールに使います。

```
$ go get github.com/gorilla/mux
```

### go test

テストファイル（`*_test.go`）を実行します。

```
$ go test
```

# データ型と基本文法

それでは本題に入り、Go のデータ型と基本的な文法について整理します。

## 基本のデータ型

基本のデータ型は次のとおりです。

|種類 |例 |
|:---|:---|
|bool|true/false|
|string|"string"|
|int|10|
|float64|3.14|

## 変数の定義

静的型付け言語なので、変数の定義時にデータ型を指定しないといけません。

```go
var fruit string = "apple"
```

`:=` を使って、次のように書くこともできます。この場合、Goが自動でデータ型を認識します。

```go
fruit := "apple"
```

一度変数を定義すれば、それ以降の操作で `var` や `:=` は要りません。

```go
fruit = "orange"
```

複数の変数を同時に定義することもできます。

```go
a, b := "apple", "orange"
```

## 関数の定義

関数を定義する場合、関数名の後に**返り値の型を指定します**。

```go
func newFruit() string {
  return "apple"
}
```

### 引数を持たせる

引数を持たせる時は、その型も指定します。

```go
func newFruit(f string) string {
  return f
}
```

### 複数の値を返す

複数の値を返す時は、それぞれの型を指定します。

```go
func newFruits() (string, string) {
  return "apple", "orange"
}
```

## for

for ループは次のように `for {}` で書きます。

```go
i := 1
for i <= 3 {
    fmt.Println(i)
    i = i + 1
}
```

`break` で処理を中断します。

```go
for {
    fmt.Println("loop")
    break
}
```

`continue` で後続の処理をスキップします。

```go
for n := 0; n <= 5; n++ {
    if n%2 == 0 {
        continue
    }
    fmt.Println(n)
}
```

## if

条件分岐は、`if {}` で次のように書きます。

```go
if 8%4 == 0 {
    fmt.Println("8 is divisible by 4")
}
```

`else if` や `else` でつなぐこともできます。

```go
if num := 9; num < 0 {
    fmt.Println(num, "is negative")
} else if num < 10 {
    fmt.Println(num, "has 1 digit")
} else {
    fmt.Println(num, "has multiple digits")
}
```

## 例外処理

Go の例外処理は `if` を使って実装します。

```go
if err != nil {
    fmt.Println("Error:", err)
}
```

利用する関数が `error` を返す場合は、その直後に例外処理を書くのが一般的です。

```go
bs, err := ioutil.ReadFile(filename)
if err != nil {
    fmt.Println("Error:", err)
}
```

## Array と Slice

Array と Slice は、どちらもいわゆる「**配列**」で、**単一のデータ型**を持つことができます。

例えば、文字列を持つ Array は「**string Array**」、文字列を持つ Slice は「**string Slice**」と言い、どちらも `[]string{}` で定義します。それぞれの例は次のとおり。

```go:Arrayの例
[2]string{"apple", "orange"}
```

```go:Sliceの例
[]string{"apple", "orange"}
```
Array と Slice の違いは、**データの長さを変更できるかどうか**です。Array は長さが固定されていますが、Slice は長さを自由に変えられます。上の例だと、Array の長さは「2」で、後から変更できません。一方 Slice の長さは、次のように変更できます。

```go
fruits := []string{"apple", "orange"}
fruits = append(fruits, "banana") // [apple orange banana]
```

空の Array と 空の Slice は、次のように定義します。

```go:Arrayの例
var fruits [2]string
```
```go:Sliceの例
fruits := make([]string, 2)
```

### Slice の基本操作

#### 値取得

0から始まる n 番目の値を取ってきます。

```go
fruits[0] 
```
範囲指定して値を取り出すこともできます。

```go
fruits[0:2] // [0] から [1] まで
fruits[:2]  // [0:2] と同義 
fruits[2:]  // [2] 以降
```
#### len

`len` で Slice の長さを調べます。

```go
len(fruits)
```
#### append

`append` で値を追加します。

```go
fruits = append(fruits, "lemon")
```

#### for, range

反復処理は、`for` と `range` を使って次のように書きます。

```go
for i, fruit := range fruits {
    fmt.Println(i, fruit)
}
```

インデックスを使わない場合は、その変数を `_` にしないといけません。

```go
for _, fruit := range fruits {
    fmt.Println(fruit)
}
```

Slice の操作をもっと知りたい場合 → [こちら](https://github.com/golang/go/wiki/SliceTricks)

## Map

Map は Ruby でいうハッシュ、JavaScript でいうオブジェクトと似たような感じで、キー・バリューのペアでデータを保持します。全てのキーと、全てのバリューは、**それぞれ同じデータ型でないといけません。**例えば、文字列キー・文字列バリューの Map は次のように定義します。

```go
colors := map[string]string{
  "red":   "#ff0000",
  "green": "#4bf745",
}
```

空の Map は次のように定義します。

```go
var colors map[string]string
// 上と同義 
colors := make(map[string]string)
```

### Map の基本操作

#### 値取得

キーを指定して値を取り出します。

```go
colors["red"] // #ff0000
```
#### 追加

新たなキーを指定することで、キー・バリューを追加できます。

```go
colors["white"] = "#ffffff"
```

#### delete

`delete` でキー・バリューを削除します。

```go
delete(colors, "white")
```

#### for, range

反復処理は、`for` と `range` を使って次のように書きます。

```go
for color, hex := range c {
    fmt.Println("Hex code for", color, "is", hex)
}
``` 

## Struct

Struct で基本データ型のデータ構造を定義すれば、それを Map（ハッシュ）のように使えます。

```go
type person struct {
    firstName string
    lastName  string
}
```

Structは、フィールドに値を渡して定義します。

```go
ken := person{firstName: "Ken", lastName: "Thompson"}
```

フィールドを指定しない場合は、定義した順番にしたがって値が割り当てられます。

```go
ken := person{"Ken", "Thompson"} // 上と同義
```

### Struct のデフォルト値

Struct のフィールドに値を入れない場合、デフォルト値が適用されます。それぞれのデータ型のデフォルト値は次のとおりです。

|種類 |デフォルト |
|:---|:---|
|bool|false|
|string|""|
|int|0|
|float64|0|

### Struct の基本操作 

各フィールドの値は、`.` メソッドのようにして取り出せます。

```go
fmt.Println(ken)           // {Ken Thompson}
fmt.Println(ken.firstName) // Ken
fmt.Println(ken.lastName)  // Thompson
```

値の更新も `.` を使って感覚的におこなえます。

```go
ken.lastName = "Anderson"
fmt.Println(ken)  // {Ken Anderson}
```

### Embedded structs（ネスト）

Struct のフィールドに別の Struct をネストさせることができます。

```go
type contactInfo struct {
  email   string
  zipCode int
}

type person struct {
  firstName string
  lastName  string
  contact   contactInfo
}
```

フィールド名とネストさせる Struct 名を統一する場合は、次のように省略して定義できます。

```go
type person struct {
  firstName string
  lastName  string
  contactInfo // contactInfo contactInfo と同義
}
```

## Map と Struct の違い

Map と Struct は似ていますが、次のような違いがあります：

* Map
    * キーは全て同じ型
    * バリューも全て同じ型
    * キーはインデックスされている（反復処理できる）
    * Reference Type（後述）
* Struct
    * 各バリューの型は自由
    * キーはインデックスされていない（反復処理できない）
    * Value Type (更新にはポインターが必要・後述)

## メソッド

関数にレシーバを持たせることで、メソッドを定義できます。

```go
type rect struct {
    width, height int
}

func (r rect) area() int {
    return r.width * r.height
}
```

上の例だと、`type rect` であれば、`area()` メソッドを呼び出せます。


```go
r := rect{width: 10, height: 5}
fmt.Println("area: ", r.area()) // area:  50
```

## Struct 更新できない問題

例えば、上のStruct `type rect` の値を更新するメソッドを書いてみます。

```go
// widthを更新するメソッド
func (r rect) updateWidth(w int) {
    r.width = w
}
```

**しかし、これを実行しても元の `width` は更新されません！**

```go
r := rect{width: 10, height: 5}
r.updateWidth(20)

fmt.Println("area: ", r.area()) // area:  50
fmt.Println(r) // {10 5}
```

### Value Type の更新

これは Struct が **Value Type** であることが原因です。Value Type をレシーバにすると、そのコピーされた値がメソッド関数に渡ってしまうからです。

これを解決するには、`&` を使って Value Type のポインターのメモリアドレスを引数に渡し、`*` を使ってそのポインター（実際の値）をレシーバに指定します。

```go
// ポインター（実際の値）をレシーバに指定
func (r *rect) updateWidth(w int) {
    r.width = w
}
```

```go
r := rect{width: 10, height: 5}
// r のポインターでメソッドを呼ぶ
rPointer := &r
rPointer.updateWidth(20)

fmt.Println("area: ", r.area()) // area:  100
fmt.Println(r) // {20 5}
```

### Value Type の更新（省略ver.）

上のようにいちいちポインターを定義しなくても、メソッド引数に `*` が使われていれば、Value Type を渡すだけで Go がそれを自動変換してくれます。なので、普通はポインターの定義を省略して書きます。

```go
r := rect{width: 10, height: 5}
r.updateWidth(20) // Go がポインターに自動変換してくれる

fmt.Println("area: ", r.area()) // area:  100
fmt.Println(r) // {20 5}
```

### Reference Type

一方の Reference Type （例えば、Slice）は、もともと別のデータメモリを参照している型なので、ポインターを使わなくても別の関数内で更新できます。

```go
func updateFruits(fruits []string) {
	fruits[0] = "lemon"
}
```

```go
fruits := []string{"apple", "orange", "banana"}
updateFruits(fruits)
fmt.Println(fruits) // [lemon orange banana]
```

Value Type と Reference Type、それぞれの一覧は次のとおりです：

#### Value Type 一覧

* int
* float64
* string
* bool
* structs


#### Reference Type 一覧

* slices
* maps
* channels
* pointers
* functions 

# Interface

Interface は、同じ振る舞い（メソッド）をもつ複数の型を１つの型にまとめるのに使います。Interface に対して共通したメソッドを書くことができます。

例えば、長方形 `rect` と、円 `circle` は、両方とも面積を計算する `area()` メソッドを持っていたとします。

```go
type rect struct {
    width, height float64
}

type circle struct {
    radius float64
}

func (r rect) area() float64 {
    return r.width * r.height
}

func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}
```

この  `area()` メソッドを持っている型を `geometry interface` とし、`measure()` メソッドを定義します。

```go
type geometry interface {
    area() float64
}

func measure(g geometry) {
    fmt.Println("area:", g.area())
}
```

`rect` と `circle` は、どちらも `geometry interface` の定義を満たしているので、`measure()` の引数として利用できます。

```go
r := rect{width: 3, height: 4}
c := circle{radius: 5}
measure(r) // area: 12
measure(c) // area: 78.53981633974483
```

## Interface の例（net/http）

Webサーバを作る時に使われる標準ライブラ、[net/http](https://golang.org/pkg/net/http/) パッケージを使って、Interface を実際に使ってみます。

```go
import "net/http"
```

### Handler

まず、[http.Handler](https://godoc.org/net/http#Handler) は、`ServeHTTP(ResponseWriter, *Request)` メソッドを持つ Interface です。

```go
type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
}
```

### ListenAndServe

そして、Webサーバの役割を成す [http.ListenAndServe](https://godoc.org/net/http#ListenAndServe) は、第２引数に `Handler` を取っています。

```go
func ListenAndServe(addr string, handler Handler) error
```

### Handler を作ってサーバを立ち上げる

つまり、`ServeHTTP()` メソッドを持つ型を作れば、それを `Handler` として扱うことができ、さらにその型を `ListenAndServe` の引数に渡せば、独自のレスポンスを返すことができます。

試しに `anything` タイプに `ServeHTTP()` を持たせて、レスポンスを返してみます。

```go:main.go
package main

import (
	"fmt"
	"net/http"
)

type anything int

func (a anything) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Any code you want in this func")
}

func main() {
	var a anything
	http.ListenAndServe(":8080", a)
}
```

`go run` コマンドでウェブサーバを起動します。

```
$ go run main.go
```

`http://localhost:8080` を叩くと、ちゃんとレスポンスが返ってきますね。

```
$ curl http://localhost:8080
Any code you want in this func
```

# Goroutines と Channels

Go はデフォルトでは Main Routine（シングルスレッド）で処理していますが、HTTPリクエストを連続して投げる時など、関数呼び出しの前に `go` をつけると、新しい Child Goroutine を作成して Concurrency 処理（マルチスレッド）にできます。

```go
go checkLink(link) // Child Goroutine で実行
```

## Child Goroutine 待たれない問題

注意点としては、ただ `go` で Child Goroutine を利用するだけだと、**Main Routine は Child Goroutine の処理を待たずに終了してしまう**ことです。

```go
func checkLink(link string, c chan string) {
	_, err := http.Get(link)
	if err != nil {
		c <- link + " might be down!"
		return
	}

	c <- link + " is up!"
}
```

```go
links := []string{"http://google.com", "http://github.com"}
c := make(chan string)
for _, link := range links {
	go checkLink(link, c)
}

for i := 0; i < len(links); i++ {
	fmt.Println(<-c)
}
```

この問題を防ぐのに使われるのが **Channels** です。

## Channels

Channels は Routines 間のコミュニケーションに使い、次のように定義します。

```go
c := make(chan string)
```

テキストメッセージサービスのようなイメージで、次のようにデータを送受信します。

```go
c <- "Some string" // 送信

<- c // 受信
```

## Channels で Child Goroutine を待つ

この Channels を使って、Main Routine が Child Goroutine の処理を待つようにします。具体的には、Child Goroutine に Channel を渡し、Child Goroutine の処理終了時にその Channel へデータを送信させます。Main Routine に受信したデータを使う処理を書いておけば、ちゃんと Child Goroutine の処理を待つことができます。

```go
// Child Goroutine に Channel を渡す
// 処理終了時にその Channel へデータを送信
func checkLink(link string, c chan string) {
	_, err := http.Get(link)
	if err != nil {
		c <- link + " might be down!"
		return
	}

	c <- link + " is up!"
}
```

```go
links := []string{"http://google.com", "http://github.com"}
c := make(chan string)

for _, link := range links {
	go checkLink(link, c)
}

// 注意: links の数だけで Channel でデータを受信する
for i := 0; i < len(links); i++ {
	fmt.Println(<-c) // 受信したデータを使う処理
}
```

ここでの注意点は、**Child Goroutine の数だけ、Main Routine にて Channel でデータを受信しないといけません。**この数が足りないと、全ての Child Goroutine の処理が終了する前に Main Routine の処理が終了してしまうからです。したがって、上の例では `links` の数だけ「受信したデータを使う処理」を反復させています。

# Goのテスト

Go でのテストは、標準ライブラリの [testing](https://golang.org/pkg/testing/) を使って、`*_test.go` ファイルにシンプルなテストコードを書いていくのが一般的です。

## *testing.T

テストコードの例は、次のとおりです（`Abs` のテスト）：

```go:xxx_test.go
func TestAbs(t *testing.T) {
    got := Abs(-1)
    if got != 1 {
        t.Errorf("Abs(-1) = %d; want 1", got)
    }
}
```

テスト関数の引数に `*testing.T` を渡し、`if` でアサーションを検証します。エラーがある場合は、`t.Errorf` で結果を失敗にします。

## TestMain(m *testing.M)

テストファイルの実行前後にセットアップなどの処理が必要なときは、`TestMain(m *testing.M)` にその処理を書きます。

```go
func TestMain(m *testing.M) {
    // setup
    code := m.Run() // テストの実行
    // teardown
    os.Exit(code) // 処理の終了
}
```

## go test

`go test` コマンドで `*_test.go` ファイルのテストを実行します。

```
$ go test
```

# References

* [Go: The Complete Developer's Guide (Golang) -  Stephen Grider](https://www.udemy.com/go-the-complete-developers-guide/)
* [Web Development w/ Google’s Go (golang) Programming Language - Todd McLeod](https://www.udemy.com/go-programming-language/)
* [Go by Example - Mark McGranaghan](https://oohira.github.io/gobyexample-jp/) 
* [Go Playground](https://play.golang.org/)
* 他、公式ドキュメントなど