Upgrade to Pro — share decks privately, control downloads, hide ads and more …

go generate 完全入門

go generate 完全入門

プログラミング言語Go完全入門 質問会
https://mercari.connpass.com/event/174255/

YAEGASHI Takeshi

June 03, 2020
Tweet

More Decks by YAEGASHI Takeshi

Other Decks in Technology

Transcript

  1. 自己紹介 八重樫 剛史 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」
  2. 今日の話題 go generate 完全入門 Go コード生成概論(?) • そもそも 5 分間の

    LT で完全入門できる ような話題ではない • プログラミング言語 Go 完全入門 に go generate がなかったので、出来 心であやかったタイトルをつけてしまっ た… 新章のアナウンス!期待しています!
  3. Go のコード生成とコードジェネレータ • コード生成 ◦ Go のプログラムをプログラムで自動生成すること • コードジェネレータ ◦

    Go のプログラムを生成するプログラム • コードジェネレータを作る ◦ いわゆるメタプログラミング = プログラムを作るプログラムを作る ◦ Go には様々なコード生成を支援する機能がある • コードジェネレータを使う ◦ Go のエコシステムでは様々なコードジェネレータが公開されている
  4. どういうときにコード生成するのか • テーブルやアセットの埋め込み ◦ 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 … コード生成のテンプレートの記述が楽になるツール
  5. コード生成を支援する Go の機能 • //go:generate ディレクティブ ◦ ソースコード中にコードジェネレータを実行するコマンドラインが書ける ◦ $GOPACKAGE

    や $GOFILE といった環境変数がコードジェネレータに渡される • コードフォーマッタ (gofmt, goimports, etc.) ◦ コード整形の標準ツール、ライブラリとしても呼び出し可能 ◦ コードジェネレータはインデントやインポートなどを気しなくてもよくなるので開発が楽 • テンプレート (text/template) ◦ 充実した機能を持つテンプレートエンジンが標準ライブラリで利用可能 • ビルドタグ ◦ // +build ignore でコードジェネレータのソースコードをビルドから除外する
  6. コード生成したくなる Go の機能 • ソースコードの静的解析 ◦ 解析が容易な Go の文法、標準ライブラリ (ast)

    によるサポート ◦ コードジェネレータは自分を呼び出したソースコードの解析が容易にできる ◦ 汎用ツール向け • 実行時のリフレクション ◦ コードジェネレータに対象のコードを取り込み reflect で調べる ◦ 特定プロジェクト専用のコード生成で静的解析が面倒くさいときに使う代替手段 ◦ struct のフィールドやタグの情報は取れるが、コメントに書いた情報などは取れない
  7. 実例: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 ... <supplementalData> <version number="$Revision$"/> <windowsZones> <mapTimezones otherVersion="7e11200" typeVersion="2019b"> ... <!-- (UTC+02:00) Cairo --> <mapZone other="Egypt Standard Time" territory="001" type="Africa/Cairo"/> <mapZone other="Egypt Standard Time" territory="EG" type="Africa/Cairo"/> ... 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
  8. 実例: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 コマンド
  9. 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
  10. go generate のベストプラクティス • Go Modules など、最近の Go に導入さ れた機能を踏まえたコード生成のベスト

    プラクティスをまとめました • このスライドで紹介した実例についての 追加のトピックもあります • 今後も内容は随時更新 本日も更新しました! https://qiita.com/yaegashi/items/d1fd9f7d0c75b2bb7446