「Effective Go」のチートシート　〜脱Go初心者〜

# [Effective Go](https://golang.org/doc/effective_go.html) とは
明快で慣用的なGoコードを書くためのTips
*日本語訳は[こちら](http://golang.jp/effective_go)

# 事前に見ておくと良いもの
[A Tour of Go](https://tour.golang.org/welcome/1)：Goチュートリアル
[How to Write Go Code](https://golang.org/doc/code.html)： 基礎
[The Go Programming Language](https://golang.org/ref/spec)：言語仕様

# チートシート
注： 筆者の主観により、項目・内容を取捨選択しました

## 整形
- `$ gofmt` ：フォーマットを整えてくれる ([ドキュメント](https://godoc.org/github.com/golang/go/src/cmd/gofmt))
- `$ goimports`：import文を整えてくれる ([ドキュメント](https://godoc.org/golang.org/x/tools/cmd/goimports))

## コメント
**コメントの頭**に、記述する「**項目名**」を書くようにする
↓
`$ godoc 項目名 | grep -i parse` 　が便利になる ([ドキュメント](https://godoc.org/golang.org/x/tools/cmd/godoc))

## 宣言のグループ化
項目間の関係を示せる

```go
var(
    countLock sync.Mutex
    inputCount uint32
    outputCount uint32
    errorCount uint32
)
```

## ゲッターとセッター
例えばフィールド名が"owner"の場合、以下のように命名する

- ゲッター： **Owner()**
- セッター： SetOwner()

## 命名
○ `MixedCaps`
○ `mixedCaps`
△ `mixed_caps`

## 再宣言と再割り当て
このようなコードは合法であり、よく用いられる

```go
f, err := os.Open(name)
if err != nil {
    // hogehoge
}

d, err := f.Stat()
```

## Type switch
switchは、インタフェース変数の動的な型を見つけるために利用することもある

```go
switch t := interfaceValue.(type) {
default:
    fmt.Printf("unexpected type %T", t)  // %T は型を出力する
case bool:
    fmt.Printf("boolean %t\n", t)
case int:
    fmt.Printf("integer %d\n", t)
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t)
case *int:
    fmt.Printf("pointer to integer %d\n", *t)
}
```

## Defer
deferを実行した関数が**リターンする直前**に、指定した関数を呼び出してくれる
ファイルのClose、ミューテックスのアンロックなどで用いられる

```go
func Contents(filename string) (string, os.Error) {
    f, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    defer f.Close()  // f.Closeは、完了時に実行される

    // 何らかの処理

    return "hoge", nil // ここで、fはクローズされる
}
```

遅延指定された関数の引数は、関数の実行時ではなく、**deferを実行した時**に評価される

```go
func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func a() {
    defer un(trace("a"))
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}

func main() {
    b()
}
```

```
// 出力結果

entering: b
in b
entering: a
in a
leaving: a
leaving: b
```

## データ
### newによる割り当て
new(T)： 新しく割り当てられたT型の**ゼロ値**の**ポインタ**を返す

```go
type SyncedBuffer struct {
    lock    sync.Mutex
    buffer  bytes.Buffer
}

p := new(SyncedBuffer)  // *SyncedBuffer型
var v SyncedBuffer      // SyncedBuffer型
```
### makeによる割り当て
make(T)： **初期化された**(=ゼロ値でない)T型の**値**を返す

makeで割り当てできるのは、**スライス**・**マップ**・**チャネル**だけ
この3つの型は使用前に初期化されている必要があるため、"make"が存在している

### newとmakeの違い

```go
// 必要以上に複雑な書き方
var p *[]int = new([]int) // スライス構造の割り当て(*p == nil)
*p = make([]int, 100, 100)

// 一般的な書き方
v := make([]int, 100) // スライスvは、100個のintを持つ配列への参照
```

### コンストラクタと複合リテラル
複合リテラル： 実行する度に新しいインスタンスを生成する式

```go
func NewFile(fd int, name string) *File {
    if fd < 0 {
        return nil
    }
    f := File{fd, name, nil, 0}
    return &f
}
```
C言語とは異なり、**関数から戻った後も、変数に割り当てたメモリは生き残る**

### 配列とスライス
|配列|スライス|
|:-:|:-:|
|**値**|**参照型**|
|メモリの配置指定や割り当て回避ができる|配列をラップしたものであり、Goで多用される|

## 初期化
### 定数の列挙「iota」

```go
type ByteSize float64
const (
    _ = iota  // 1番目の値(0)を無視
    KB ByteSize = 1<<(10*iota)
    MB
    GB
    TB
)
```

### init関数
用途は主に2つ

- **宣言として記述できない初期化処理**を行う
- 処理を開始する前に、**状態のチェック/修正**を行う

```go
func init() {
    if USER == "" {
        log.Fatal("$USER not set")
    }
    if HOME == "" {
        HOME = "/usr/" + USER
    }
    if GOROOT == "" {
        GOROOT = HOME + "/go"
    }
    // GOROOTはコマンドラインから--gorrotフラグを指定することで上書き可能
    flag.StringVar(&GOROOT, "goroot", GOROOT, "Go root directory")
}
```

## その他
以下は後日追記するかも

- インターフェース
- 埋め込み
- 並列性
- エラー処理