> Source: https://www.ymotongpoo.com/works/goblog-ja/generate/


# コードのジェネレート
[Generating code](https://blog.golang.org/generate) by Rob Pike

普遍的な計算の性質であるチューリング完全性とは、コンピュータプログラムがコンピュータプログラムを書けるということです。
これは、頻繁に起きているにもかかわらず、実際に評価されるべきほどには評価されていない、強力な考え方です。たとえば、これはコンパイラの定義の
大きな部分を占めています。また `go test` コマンドの動作にも関わってきます。 `go test` はテスト対象の
パッケージをスキャンして、そのパッケージ用のテストハーネスを含んだGoプログラムを書き出して、
それをコンパイルして実行します。現代のコンピュータは非常に速いので、このコストが高そうな一連の処理も
ほんの一瞬で完了できます。

プログラムがプログラムを書く例は他にもたくさんあります。たとえば [Yacc](http://golang.org/cmd/yacc/) は、
文法の記述を読み込んで、文法をパースするプログラムを書き出します。Protocol Bufferの「コンパイラ」は
インターフェースの記述を読み込んで、構造の定義とメソッドとその他必要なコードを生成します。
あらゆる種類の設定ツールも同様の動作をします。メタデータや環境を確認して、ローカルの状態に合わせた
足場を生成してくれます。

それゆえプログラムを書くプログラムはソフトウェアエンジニアリングにおいて重要な要素ですが、
ソースコードを生成するYaccのようなプログラムは、その出力がコンパイルされるように
ビルドプロセスに組み込まれる必要があります。Makeのような外部のビルドツールが使われる場合、
これは非常にたやすいことです。しかしGoでは、go toolがソースコードから必要なビルド情報を
すべて取得するので、問題があります。go toolだけでYaccを走らせる簡単な機構がないのです。

いままでは、ありませんでした。

[最新のGoのリリース](http://blog.golang.org/go1.4)である、1.4ではそのようなツールを実行しやすくする
新しいコマンドが追加されました。 `go generate` というコマンド名で、Goのソースコード内の特別なコメントを
スキャンすることで動作します。 `go generate` は `go build` の一部ではないことを理解するのが大切です。
`go generate` は依存性の解析はまったく行わず、また明示的に `go build` の前に実行されなければなりません。
`go generate` はGoパッケージの利用者ではなく、その作者が利用することを意図したものです。

`go generate` コマンドは簡単に使えます。準備運動として、Yaccの文法を生成する方法を紹介しましょう。
たとえば、ここに `gopher.y` というYaccの入力用ファイルがあったとします。このファイルでは
あなたの新しい言語の文法が定義してあるとします。この文法を実装するGoのソースファイルを生成するには
通常であれば標準でついてくるGo版のYaccを次のように起動するでしょう。

```console
go tool yacc -o gopher.go -p parser gopher.y
```

`-o` オプションは出力ファイル名を指定し、 `-p` オプションはパッケージ名を指定します。

`go generate` にこの処理を行わせるには、同じディレクトリ内の通常の（自動生成でない） `.go` ファイルのいずれかに、
ファイル内のどこかに次のようなコメントを追加します。

```go
//go:generate go tool yacc -o gopher.go -p parser gopher.y
```

このテキストは先のコマンドに、 `go generate` が認識するための特別なコメントを先頭に付けただけのものです。
コメントは行頭から開始しなくてはならず、また `//` と `go:generate` の間にスペースを入れてはいけません。
そのマーカー以降は `go generate` が実行するコマンドを指定します。

では実行してみましょう。ソースのディレクトリに移動し、 `go generate` を実行して、 `go build` 等を実行します。

```console
$ cd $GOPATH/myrepo/gopher
$ go generate
$ go build
$ go test
```

これだけです。エラーが無かった場合、 `go generate` は `yacc` を起動して `gopher.go` を生成します。
そして生成されると、そのディレクトリには必要なGoのソースコードが揃うので、ビルドしてテストして
いつもどおりの処理を行えます。 `gopher.y` が変更されるたびに、 `go generate` を実行して
パーサーを再度生成しましょう。

`go generate` の動作やオプション、環境変数の内容などを知りたい場合は、
[デザインドキュメント](http://golang.org/s/go1.4-generate)を参照してください。

go generateはMakeや他のビルド機構で出来なかったことはなにもできませんが、 `go` ツールに付随するもの、
つまり余計なインストールが要らず、Goのエコシステムに上手く適用できます。 `go generate` はパッケージの
作者が使うためのものであり、パッケージの利用者のためのものではないことを心に留めておいてください。
理由の1つとして、 `go generate` が呼び出すプログラムが対象のマシンにインストールされているとは
限らないということが挙げられます。また、もし生成されたコードを含むパッケージが `go get` でインポート
されることを意図しているのであれば、生成された（そしてテストされた！）ファイルはあとに
ソースコードリポジトリに追加され、利用者が使えるようにしておく必要があります。

`go generate` について少しわかったところで、なにか新しいことをしてみましょう。
`go generate` が役に立つまったく別の例としては、 `golang.org/x/tools/` 内の `stringer` と呼ばれる、
新しいプログラムがあります。これは整数の定数に対して自動的に `String` メソッドを書いてくれます。
このツールはリリースでは配布されていませんが、簡単にインストールできます。

```console
$ go get golang.org/x/tools/cmd/stringer
```

[`stringer`](http://godoc.org/golang.org/x/tools/cmd/stringer) のドキュメントからの例を持ってきました。
あるコードに異なる錠剤の種類を定義するための整数の定数があったとします。

```go
package painkiller

type Pill int

const (
    Placebo Pill = iota
    Aspirin
    Ibuprofen
    Paracetamol
    Acetaminophen = Paracetamol
)
```

デバッグ用途にこれらの定数を綺麗に表示したい、つまりシグネチャ付きのメソッドが欲しくなります。

```go
func (p Pill) String() string
```

手でそのコードを書くのは簡単です。おそらく次のようになるでしょう。

```go
func (p Pill) String() string {
    switch p {
    case Placebo:
        return "Placebo"
    case Aspirin:
        return "Aspirin"
    case Ibuprofen:
        return "Ibuprofen"
    case Paracetamol: // == Acetaminophen
        return "Paracetamol"
    }
    return fmt.Sprintf("Pill(%d)", p)
}
```

もちろん他にもこの関数を書く方法があります。stringのスライスをPillでインデックスを
つけることもできますし、mapを使うこともできますし、他の技もあります。どのような方法でも、
錠剤のセットが変わったらそれに合わせてコードを変更する必要がありますし、それが必ず正しいように
する必要があります。（パラセタノールは2つの名前があるので他の錠剤より用心しなければなりません。）
加えて、型や値、たとえば符号有りか符号無しか、密か疎か、ゼロ基準か否かなど、に応じてどの手法を
採用するかを考えなければなりません。

`stringer` のプログラムはこれらの疑問に対してすべて面倒を見てくれます。
`stringer` は単体で動くプログラムではありますが、 `go generate` から呼び出すことを
意図されています。使うためにはソース、おそらく型定義の近くに、生成用のコメントを加えてください。

```go
//go:generate stringer -type=Pill
```

このルールでは `go generate` は `stringer` ツールを実行して `Pill` 型に `String` メソッドを
生成するように指定しています。出力結果は自動的に `pill_string.go` に書き込まれます。
（ `-output` フラグを使って出力先を変更できます。）

実行してみましょう。

```shell-session
$ go generate
$ cat pill_string.go
// generated by stringer -type Pill pill.go; DO NOT EDIT

package painkiller

import "fmt"

const _Pill_name = "PlaceboAspirinIbuprofenParacetamol"

var _Pill_index = [...]uint8{0, 7, 14, 23, 34}

func (i Pill) String() string {
    if i < 0 || i+1 >= Pill(len(_Pill_index)) {
        return fmt.Sprintf("Pill(%d)", i)
    }
    return _Pill_name[_Pill_index[i]:_Pill_index[i+1]]
}
$
```

`Pill` の定義や定数を変更するたびに、 `String` メソッドを更新するために、
次のコマンドを実行する必要があります。

```console
$ go generate
```

もちろん、同じパッケージには同様の型が複数あるので、それらの `String` メソッドすべてを
1回のコマンドで更新できるのです。

生成されるコードが醜いのは疑問の余地がありません。でもいいんです。人間がそのコードを
編集する必要はないですから。機械が生成したコードはしばしば醜いものです。醜いコードも
最適化の結果なのです。すべての名前が1つの文字列に押し込められています。こうすることで
メモリを節約しています。（すべての名前に対して、1つの文字列のヘッダだけですみます。
たとえ名前が何億兆あったとしてもです。）そして、配列の `_Pill_index` を作り、単純で
効率的な手法で値から名前への対応を作ります。 `_Pill_index` はスライスではなく `uint8` の
配列であることに気をつけてください（スライスでない分、さらにもう1つヘッダが削減されています）。
`uint8` の配列なのは、値の空間をつなぐのに
必要十分な最小の整数だからです。もっと多くの値がある、あるいは負の値がある場合には、
生成される `_Pill_index` の型は `uint16` や `int8` になるでしょう。ようするに、対応ができる
ベストな型です。

`stringer` が生成するメソッドで使われている手法は定数のセットの特性によって変化します。
たとえば、定数が疎の場合は、マップが使われます。2の累乗を表す定数のセットを使った例です。

```go
const _Power_name = "p0p1p2p3p4p5..."

var _Power_map = map[Power]string{
    1:    _Power_name[0:2],
    2:    _Power_name[2:4],
    4:    _Power_name[4:6],
    8:    _Power_name[6:8],
    16:   _Power_name[8:10],
    32:   _Power_name[10:12],
    ...,
}

func (i Power) String() string {
    if str, ok := _Power_map[i]; ok {
        return str
    }
    return fmt.Sprintf("Power(%d)", i)
}
```

手短に言えば、自動でメソッドを生成させたほうが、人間が書くよりもより効率的なものが生成できるということです。

Goのコードベースにはすでに多くの `go generate` の事例があります。 `unicode` パッケージでのUnicode表の生成や、
`encoding/gob` で配列を効率的にエンコードあるいはデコードするメソッドの作成、`time` パッケージでのタイムゾーンデータの
生成などがあります。

ぜひ `go generate` を創造的に使ってください。いろいろ試せるように公開しているのです。

`go generate` を自分で使うのではない場合にも、ぜひ `String` メソッドを書く際には新しい `stringer` ツールを使ってください。
機械に仕事をさせましょう。

## あわせて読みたい

* [Introducing the Go Race Detector](https://blog.golang.org/race-detector)
* [Go maps in action](https://blog.golang.org/go-maps-in-action)
* [go fmt your code](https://blog.golang.org/go-fmt-your-code)
* [Organizing Go code](https://blog.golang.org/organizing-go-code)
* [Debugging Go programs with the GNU Debugger](https://blog.golang.org/debugging-go-programs-with-gnu-debugger)
* [The Go image/draw package](https://blog.golang.org/go-imagedraw-package)
* [The Go image package](https://blog.golang.org/go-image-package)
* [The Laws of Reflection](https://blog.golang.org/laws-of-reflection)
* [Error handling and Go](https://blog.golang.org/error-handling-and-go)
* ["First Class Functions in Go"](https://blog.golang.org/first-class-functions-in-go-and-new-go)
* [Profiling Go Programs](https://blog.golang.org/profiling-go-programs)
* [A GIF decoder: an exercise in Go interfaces](https://blog.golang.org/gif-decoder-exercise-in-go-interfaces)
* [Introducing Gofix](https://blog.golang.org/introducing-gofix)
* [Godoc: documenting Go code](https://blog.golang.org/godoc-documenting-go-code)
* [Gobs of data](https://blog.golang.org/gobs-of-data)
* [C? Go? Cgo!](https://blog.golang.org/c-go-cgo)
* [JSON and Go](https://blog.golang.org/json-and-go)
* [Go Slices: usage and internals](https://blog.golang.org/go-slices-usage-and-internals)
* [Go Concurrency Patterns: Timing out, moving on](https://blog.golang.org/go-concurrency-patterns-timing-out-and)
  * [Goの並行パターン：タイムアウトと進行](../go-concurrency-patterns-timing-out-and/)
* [Defer, Panic, and Recover](https://blog.golang.org/defer-panic-and-recover)
* [Share Memory By Communicating](https://blog.golang.org/share-memory-by-communicating)
* [JSON-RPC: a tale of interfaces](https://blog.golang.org/json-rpc-tale-of-interfaces)
