-
Notifications
You must be signed in to change notification settings - Fork 3
metagoを作った話 #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
metagoを作った話 #40
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
リポジトリ
metagoはGo言語向けのメタプログラミングライブラリです。
考え方のベースとしてwireのシグニチャを定義し実装は機械的に生成する考え方と、VのReflection via codegenのホスト言語の構文でメタ構造を書く、というのを使っています。
本ライブラリはある程度動きますが、現時点ではトップレベルの定義を生成したり動的な名前のメソッドを生成したりすることはできません。
テストケースも圧倒的に不足しているため実用レベルに達しているかといわれると疑問があります。
モチベーション
Goは言語自体の持つ型の表現力が弱く、ボイラープレートなコードをたくさん書くことになりがちです。
そこで、何らかのデータを元にGoのコードを自動生成しよう!というアイディアに至るのに時間はかかりません。
一番最初に思いつくであろう、GoのコードをASTで組み立てる戦略は破滅的にめんどくさいです。
これは、生成したいと思っているGoのコードとASTを組み立てるコードにまったくもって相似ではないからです。
次のアイディアとして、Goのコードをテキストとして組み立てるものがあります。
jwgでは
Printf
を使ってソースコードを生成しています。gqlgenでは
text/template
を使ってソースコードを生成しています。これは、ASTを使って組み立てるのに比べるとだいぶ仕上がりが想像しやすいです。
一方でIDEからの支援が得にくく、出力後のコードがvalidなコードかというのは出力してみるまでわかりません。
新しいアプローチとして、本ライブラリ metago を考え、実装しました。
metagoでは生成するべきGoのコードをGoのコードで書きます。
鋳型になるGoコードのASTをこねこねして、ほしいGoコードに変換するイメージです。
これならば、IDEの支援を今までに比べると圧倒的に楽に実装することができます。
metago について
metagoでは、実際のソースコード中にマーカーを仕込んでいき最終的なソースコードを生成します。
あるオブジェクトのフィールド名と値を出力するテンプレートは次のようになります。
これをmetagoで処理すると次のコードが得られます。
実際にプログラムとして動作させるのはこちらの生成されたコードです。
reflectパッケージに少し似ています。
どういったことができるかというのはtestbedディレクトリを見てみてください。
主なfeatureとして…
mv := metago.ValueOf(obj)
によってmetago.Value
な値を取得for _, mf := range mv.Fields()
によって各フィールドに対する処理を展開・記述mf.Name()
によってフィールド名の取得mf.Value()
によってフィールドの値の取得mf.StructTagGet("json")
などでstructのタグの取得mf.Value().(time.Time)
といった型アサートとif文の組み合わせによるフィールドの型毎の処理の振り分けmv metago.Value
の関数)の利用などに対応しています。
metago のインストールと実行