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. go generate 完全入門
    2020-06-03 プログラミング言語Go完全入門 質問会
    Takeshi Yaegashi

    View Slide

  2. 自己紹介
    八重樫 剛史 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」

    View Slide

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

    View Slide

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

    View Slide

  5. どういうときにコード生成するのか
    ● テーブルやアセットの埋め込み
    ○ 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 … コード生成のテンプレートの記述が楽になるツール

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  9. 実例: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

    View Slide

  10. 実例: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 コマンド

    View Slide

  11. 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

    View Slide

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

    View Slide

  13. おわり
    Happy Go code generating!

    View Slide