Go メモ

## 記法
MixedCaps or mixedCaps
戦闘が大文字の場合,パッケージ外にエクスポートされることを意味する

## 変数宣言
変数名　型　で宣言

```go
j int = 1
```

varで複数の変数を宣言できる

```go
var i, j int = 1, 2
```

## 暗黙の変数宣言
**関数内でのみ** `:=`で暗黙的な変数の宣言が可能

```go
func main() {
    k := 3
}
```

## 型変換の明示
Goではint型とfloat型などでも明示的に変換しないとエラーをはく
暗黙の変数宣言の際は代入される値から推論

## ループ
whileみたいに書きたいときはforの宣言とイテレータを書かないことで実現する

```go
for sum < 1000 {
    sum += sum
}
```
ループ条件を抜くことで無限ループを簡潔に記述することもできる

## if
ifの条件式中に変数を書くことができる
変数はifやelse文の中でのみ有効

```go
if v := math.Pow(x, n); v < lim {
    return v
}
```

## switch
該当するcaseのみを実行
caseは定数である必要がない
breakは自動的に入るので書く必要なし

## defer
deferに渡した関数は呼び出し元の関数がreturnされたあとに実行される
複数ある場合はあとに渡したものから実行される

```golang
func main() {
   defer fmt.Println("こちらがあと")
   fmt.Println("こちらが先")
}
```

## ポインタ

```golang
var p *int
i := 42
p = &i
fmt.Println(*p) // 42
```

## 配列
配列のサイズは変えることはできない
`a[low:high]`でスライスできる(high-1までとれる)
※スライスはあくまでもとの配列への参照

以下のスライスは等価

```golang
a[0:10]
a[:10]
a[0:]
a[:]
```

`len()`で長さ,`cap()`で容量を取得できる
ここでいう容量とはスライスの最初の要素から数えてもととなる配列の要素数である

make関数を利用するうことで動的サイズの配列を作成できる
`make([]type, length, capacity)`
makeでつくった配列をスライスした場合,中身はゼロ値で埋められる

## map
Rubyのハッシュ, Pythonの辞書てきなやつ

```go
map[Type]Type // "":""のmap 
```

## closure(クロージャ)
クロージャは、それ自身の外部から変数を参照する関数値
関数を返す関数で初期化すると関数を返す関数内の変数の値を保持できる
使い所が難しいそう…

## Methods
Goにはクラスの仕組みはないがmethodを定義できる

```go
// 型に生やす場合
func (変数 生やしたい型) methodName(引数 型) 返却する型 {}
// 通常の関数
func methodName(引数 型) 返却する型 {}
```

※レシーバ(メソッドの呼び出される側→fmt.Printlnのfmt)を伴うメソッドの宣言はレシーバ型が同じパッケージに存在する必要がある

Methodには引数のコピーを渡すため,引数となる値そのものを変えたい場合はポインタレシーバにする必要がある
https://go-tour-jp.appspot.com/methods/4

以下のような時,vは変数だがポインタレシーバを保つ場合,`v.Scale(2)`を`(&v).Scale(2)`として解釈する

```go
func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	v.Scale(2)
	fmt.Println(v) // &{6, 8}
}

```

逆にポインタを変数として解釈も可能
この場合、 p.Abs() は (*p).Abs() として解釈される

```golang
func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
	p := &Vertex{4, 3}
	fmt.Println(p.Abs())
}
```

ポインタレシーバを使う理由
1. レシーバが指す先の変数を変えたい
2. メソッド呼び出しのたびの変数のコピーを避けるため
一般的には変数レシーバかポインタレシーバのどちらかで統一すべき

## interface
メソッドのシグニチャの集まりで定義
メソッドを定義した変数をinterface型に持たせることができる
https://go-tour-jp.appspot.com/methods/9

interfaceの説明
https://qiita.com/tenntenn/items/eac962a49c56b2b15ee8

空のインターフェースは任意の型の値を保持できる．
`var i interface{}`

インターフェースの値愛が具体的な型を保持し，　その方の値を`t`ni
代入することを意味する
成功したかのbool値も取れる
もしfalseの場合, Typeのゼロ値が代入される

```go
t := i.(Type)
t, ok := i.(Type) // ok = true, false
```

以下はStringerインターフェースを使ってfmt.Stringerインターフェースを実装している
つまりstringとして扱うことができる

```go
type Person struct {
	Name string
	Age  int
}

func (p Person) String() string {
	return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func main() {
	a := Person{"Arthur Dent", 42}
	z := Person{"Zaphod Beeblebrox", 9001}
	fmt.Println(a, z)
}
```

エラー状態を`error`インターフェースで実装する
一般的にはerror変数がnilなら成功，　それ以外ならErrorを出力と言った形をとる
Errorの中身を以下のように作っておくことも多い

```go
i, err := strconv.Atoi("42")
if err != nil {
    fmt.Printf("couldn't convert number: %v\n", err)
    return
}
fmt.Println("Converted integer:", i)

```

```go
type MyError struct {
	When time.Time
	What string
}

func (e *MyError) Error() string {
	return fmt.Sprintf("at %v, %s",
		e.When, e.What)
}
```

## 並列処理　goroutine
並列処理周り
`select`がよくわからなかった

```go
func sum(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum // send sum to c
}

func main() {
	s := []int{7, 2, 8, -9, 4, 0}

	c := make(chan int)
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)
	x, y := <-c, <-c // receive from c

	fmt.Println(x, y, x+y)
}
````


# Exercise
## Map

```go

func WordCount(s string) map[string]int {
	wordCounter := make (map[string]int)
	words := strings.Fields(s)
	fmt.Println(words)  
	for i := 0; i < len(words); i++ {
		_, ok := wordCounter[words[i]]
		if ok {
			wordCounter[words[i]] += 1
		} else {
			wordCounter[words[i]] = 1
		}
	}
	return wordCounter
}

func main() {
	wc.Test(WordCount)
}
```

## Stringers

```go
package main

import "fmt"

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.
func (ip IPAddr) String() string {
	return fmt.Sprintf("%v.%v.%v.%v", ip[0], ip[1], ip[2], ip[3] )
}

func main() {
	hosts := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
	for name, ip := range hosts {
		fmt.Printf("%v: %v\n", name, ip)
	}
}
```

## Errors

```go
package main

import (
	"fmt"
)

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
	return fmt.Sprintf("cannot Sqrt negative number: %g", float64(e))
}

func Sqrt(x float64) (float64, error) {
	x64 := float64(x)
    xn := float64(0)
    n  := 10
    
	if x < 0 {
		return 0, ErrNegativeSqrt(x)
	}
	
    for ; xn * xn < 64; xn++ {
    }
    
    for i := 0; i < n; i++ {
    	xn = (xn + x64 / xn) / 2
    }
    
    return xn, nil
}

func main() {
	fmt.Println(Sqrt(2))
	fmt.Println(Sqrt(-2))
}

```


# Gpを正しく書くために
`gofmt` ファイルフォーマッター
`goimport` gofmtの上位互換．　import周りを挿入削除してくれる
`go vet` バグになりそうなコードの検出
`golint` Goらしくないコードを検出

# プロジェクト
プロジェクト名は __小文字__
testdata/や_で始まるディレクトリはGoのパッケージとしてみなさない

# ライブラリ
https://qiita.com/hatai/items/f31914f37dc6c53b2bce

### Web Application FrameWork
- Gin
- Echo
- Iris
- Goa

### O/R マッパー
- Xorm
- GORM

http://gorm.io/docs/query.html

- gorp
- beego orm

### 環境変数， 設定, key管理
- toml

https://github.com/BurntSushi/toml

# APIの作り方
https://thenewstack.io/make-a-restful-json-api-go/