Open24

go generate(する方)に入門する

nfurudononfurudono

go generateでコード生成できることは知っているけど、具体的にどんなツールがあって何を実装すると生成できるか知らない。
また、簡単に生成するためのツールとか、ベストプラクティスがあるかもと思いつつ、やはり知らない。

そういうわけでガッと調べてみる。


結果的に、リリース時の公式ブログ、サンプル実装として今も公開されてるstringerの実装、デザインドキュメントを読んだ。

Goのツールとしていい感じにプログラムを呼び出してくれる仕組みなのだと理解した。
なので、コード生成しない使い方もできるっちゃできそう。例えばlinterを呼び出すエントリーポイントにするとか。
design docでも述べられているけど、makeの結構な部分を置き換えられそうで、コード生成に限らず色々できると思う。
Linter呼び出すのが嬉しいか微妙だけど。ぼくは新しく参加したプロジェクトで静的解析の実行のためにはgo generateしようと言われたびっくりする。makeでいいじゃんってなりそう。

ソースコードにディレクティブを書いてトリガーできるのがやはり特に嬉しいポイントなのかな。

ベストプラクティスみたいなものは結局見つけていない。そんなものはない気もする

nfurudononfurudono

Programs that write programs are therefore important elements in software engineering, but programs like Yacc that produce source code need to be integrated into the build process so their output can be compiled. When an external build tool like Make is being used, this is usually easy to do. But in Go, whose go tool gets all necessary build information from the Go source, there is a problem. There is simply no mechanism to run Yacc from the go tool alone.

Until now, that is.

とのこと。なるほどgo generateはgoをコンパイルする直前にgoコードを生成するステップを組み込むために存在するのか

nfurudononfurudono

パッケージ名を指定できるとか、go generate以外(人が温かみのある作業で書くとか)で作られたコードにgo generateの実行を書けるがmakeで頑張ることに対する優位性かな

nfurudononfurudono

Cのあの本とかプログラミング作法で読んだような雰囲気だと思ったらRob Pikeのコミットだった

nfurudononfurudono

stringer面白かった。実装は単一ファイルで読み易い

nfurudononfurudono

go generateで指定するコマンドは、特に難しいこと考えずにGoコード生成するとよさそう

ただし、入力となるパッケージを拡張するコードを書きたいなら、go generateをダイレクティブから呼ばれることを気にすることになりそう

nfurudononfurudono

ソースコードを入力にしようと思おうと、GoのspecとAST表現を暗記すると話が早そう

nfurudononfurudono

The go generate tool also sets the build tag “generate” so that files may be examined by go generate but ignored during build.

build tagってなんだろ

nfurudononfurudono

thanks gpt、それっぽい

buildタグは、Goのビルドシステムで使用される特別なコメントです。特定の条件に基づいてファイルを含めるかどうかを制御するために使います。このタグは、ソースコードファイルの最初に記述され、ビルド時にGoツールがそのファイルをどのように扱うかを指定できます。

たとえば、// +build generateというコメントは、そのファイルがgo generateコマンドでのみ使用され、通常のビルドでは無視されることを示します。これにより、生成されたコードやツール固有のコードをビルドから除外できます。

簡単に言うと、buildタグは特定の環境や条件下でのみファイルをビルドに含めるかどうかを決定する仕組みです。go generateの場合、// +build generateタグが付けられたファイルは、通常のビルドには影響を与えませんが、go generateコマンドで処理することができます。

例えば、次のように記述します:

// +build generate

package main

// このファイルは go generate コマンドで使用されるため、通常のビルドでは無視されます。

これにより、go buildgo runではこのファイルはビルドされませんが、go generateでは処理されます。

nfurudononfurudono

なるほどね (thanks gpt)

-tagsオプションは、Goのコマンド(例:go build, go test, go run)で使用され、ビルドタグを指定するためのものです。このオプションを使うことで、特定のビルドタグを持つファイルを含めたり除外したりできます。

Goでは、ファイルに「ビルドタグ」を記述することで、特定の条件下でのみそのファイルをビルド対象に含めることができます。-tagsオプションは、これらのタグを指定して、Goツールに特定のファイル群を処理させることを意味します。

使用方法

goコマンドに対して-tagsオプションを使うと、指定したタグに一致するファイルだけを対象に処理します。

例えば、次のように使います:

go build -tags=generate

このコマンドは、// +build generateタグを持つファイルのみをビルド対象として扱います。generateタグを持たないファイルはビルドされません。

複数のタグを指定する

複数のタグを指定することもできます。タグをカンマ区切りで列挙すると、いずれかのタグが一致するファイルが対象としてビルドされます。例えば:

go build -tags="linux,arm"

この場合、// +build linuxまたは// +build armタグを持つファイルがビルド対象として選ばれます。

-tagsの使いどころ

  • 環境ごとの処理: 例えば、特定のプラットフォームやアーキテクチャに依存したコードを含める場合、タグを使ってそれを管理できます。
  • ツールの生成: go generateやテストなどで、特定のコードを自動生成するファイルを含めるために-tagsを使います。

まとめ

-tagsオプションを使うことで、ビルド時に特定のビルドタグを持つファイルを処理対象にしたり、除外したりできます。この機能は、環境ごとの設定や生成コードを扱う際に非常に便利です。

nfurudononfurudono

なるほど〜

最終的にどうなったんだろう。ぼくの中では不整合を検知していない

nfurudononfurudono

次は実際にコード生成ツールを作ってみて、動かしてみるかな