Slide 1

Slide 1 text

go generate 完全入門 2020-06-03 プログラミング言語Go完全入門 質問会 Takeshi Yaegashi

Slide 2

Slide 2 text

自己紹介 八重樫 剛史 Takeshi Yaegashi ● 株式会社バンダイナムコスタジオ所属 ● Linux・Unix・OSS・低レベルなことが好きなエンジニア ● ブログ https://l0w.dev Qiita https://qiita.com/yaegashi ● 最近の仕事 ○ Raspberry Pi IoT 案件 (Go) スマホゲームアプリのサーバ開発 (Go) ○ 社内向け研究・開発インフラ構築 ● 過去の登壇 ○ Go Conference 2019 Autumn「Microsoft Graph API Library for Go」

Slide 3

Slide 3 text

今日の話題 go generate 完全入門 Go コード生成概論(?) ● そもそも 5 分間の LT で完全入門できる ような話題ではない ● プログラミング言語 Go 完全入門 に go generate がなかったので、出来 心であやかったタイトルをつけてしまっ た… 新章のアナウンス!期待しています!

Slide 4

Slide 4 text

Go のコード生成とコードジェネレータ ● コード生成 ○ Go のプログラムをプログラムで自動生成すること ● コードジェネレータ ○ Go のプログラムを生成するプログラム ● コードジェネレータを作る ○ いわゆるメタプログラミング = プログラムを作るプログラムを作る ○ Go には様々なコード生成を支援する機能がある ● コードジェネレータを使う ○ Go のエコシステムでは様々なコードジェネレータが公開されている

Slide 5

Slide 5 text

どういうときにコード生成するのか ● テーブルやアセットの埋め込み ○ go-bindata, go-assets, statik … ファイルの内容を文字列リテラルに変換するツール ● 仕様書を元にしたコードの自動生成 ○ time, wtz.go … Windows タイムゾーン対応表の XML から map リテラルを生成している ○ msgraph.go … OData 仕様書の XML から API のコードを生成している ○ go-swagger … Open API 仕様書の YAML から API のコードを生成するツール ● コードを元にしたコードの自動生成 ○ stringer … コードを静的解析して const 定義から文字列を生成するツール ○ wire … コードを静的解析して DI のコードを生成するツール ● ジェネリクスやマクロの代替手段 ○ genny … コード生成のテンプレートの記述が楽になるツール

Slide 6

Slide 6 text

なぜコード生成するのか ● コーディングに必要な筋力の削減、つまらないミスの防止 ○ 似たようなコードを繰り返し人間が書くのは最小限にしたい ● 動的なデータや型、リフレクションを避ける ○ 静的なコードを徹底することで得られるメリット ■ 実行時のパフォーマンスの最適化 ■ 開発時のコーディング支援の最大化

Slide 7

Slide 7 text

コード生成を支援する Go の機能 ● //go:generate ディレクティブ ○ ソースコード中にコードジェネレータを実行するコマンドラインが書ける ○ $GOPACKAGE や $GOFILE といった環境変数がコードジェネレータに渡される ● コードフォーマッタ (gofmt, goimports, etc.) ○ コード整形の標準ツール、ライブラリとしても呼び出し可能 ○ コードジェネレータはインデントやインポートなどを気しなくてもよくなるので開発が楽 ● テンプレート (text/template) ○ 充実した機能を持つテンプレートエンジンが標準ライブラリで利用可能 ● ビルドタグ ○ // +build ignore でコードジェネレータのソースコードをビルドから除外する

Slide 8

Slide 8 text

コード生成したくなる Go の機能 ● ソースコードの静的解析 ○ 解析が容易な Go の文法、標準ライブラリ (ast) によるサポート ○ コードジェネレータは自分を呼び出したソースコードの解析が容易にできる ○ 汎用ツール向け ● 実行時のリフレクション ○ コードジェネレータに対象のコードを取り込み reflect で調べる ○ 特定プロジェクト専用のコード生成で静的解析が面倒くさいときに使う代替手段 ○ struct のフィールドやタグの情報は取れるが、コメントに書いた情報などは取れない

Slide 9

Slide 9 text

実例:time (Windows タイムゾーン変換 map 生成) var abbrs = map[string]abbr{ "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo "Morocco Standard Time": {"+00", "+01"}, // Africa/Casablanca "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg "Sudan Standard Time": {"CAT", "CAT"}, // Africa/Khartoum ... ... ... Windowsタイムゾーン仕様 windowsZones.xml 生成された map リテラル zoneinfo_abbrs_windows.go //go:generate env ZONEINFO=$GOROOT/lib/time/zoneinfo.zip go run genzabbrs.go -output zoneinfo_abbrs_windows.go //go:generate を含む zoneinfo.go

Slide 10

Slide 10 text

実例:stringer (const の型に String() メソッド生成) const _Pill_name = "PlaceboAspirinIbuprofenParacetamol" var _Pill_index = [...]uint8{0, 7, 14, 23, 34} func (i Pill) String() string { if i < 0 || i >= Pill(len(_Pill_index)-1) { return "Pill(" + strconv.FormatInt(int64(i), 10) + ")" } return _Pill_name[_Pill_index[i]:_Pill_index[i+1]] } type Pill int const ( Placebo Pill = iota Aspirin Ibuprofen Paracetamol Acetaminophen = Paracetamol ) //go:generate go run golang.org/x/tools/cmd/stringer -type=Pill Pill の String() メソッドが 生成された pill_string.go Pill 型の const 定義と //go:generate を含む pill.go go run で呼び出す stringer コマンド

Slide 11

Slide 11 text

Go のコード生成を深く知るための資料 ● 自由度が高いゆえにわかりにくい・まちがいやすい ● go generate のマニュアルを読む ○ https://golang.org/cmd/go/#hdr-Generate_Go_files_by_processing_source ○ go help generate で読める ● go generate 登場時の記事を読む (Go 1.4 の頃; 2014 年末) ○ The Go Blog: Generating code https://blog.golang.org/generate ■ stringer を例として詳しく説明している ○ Go ganerate: A proposal https://golang.org/s/go1.4-generate

Slide 12

Slide 12 text

go generate のベストプラクティス ● Go Modules など、最近の Go に導入さ れた機能を踏まえたコード生成のベスト プラクティスをまとめました ● このスライドで紹介した実例についての 追加のトピックもあります ● 今後も内容は随時更新 本日も更新しました! https://qiita.com/yaegashi/items/d1fd9f7d0c75b2bb7446

Slide 13

Slide 13 text

おわり Happy Go code generating!