はじめに
- 前回 go generate について調べたので自分でもなにか作ってみたくなった。
- 構造体フィールドのタグでバリデーションやデフォルト値の設定ができるものがあると便利だと思ったので作ってみる。
- 有名なもので validator とかあるがデフォルト値を指定できないし、遅いとよく聞く reflect を使っているので generate でバリデータを生成するものを作っても多少は有用そう。
- ただ本当に reflect が遅いかどうかを実際に計測したことがないので確認してみる。
比較のためにつくるもの
- Go では他の言語の名前付き引数のようなことをしたい場合に
type MyArg struct { Arg1, Arg2 int }
のような小さい構造体を作ってMyFunc(MyArg{ Arg1: 1, Arg2: 2 })
のように使うパターンが有る。 - このとき引数用の構造体のフィールドのタグで引数のバリデーションやデフォルト値の設定ができるようなものをつくってみる。
- とりあえず比較のための仮実装なので
int
型だけ対応する。
type MyArg struct {
// タグの arg キーでオプションを指定できる
Arg1 int `arg:"default=5"`
// オプションはカンマ区切りで複数指定できる
// `name=val` という形式で、最小値チェックの `min`、最大値チェックの `max`、デフォルト値設定の `default` だけ実装する
Arg2 int `arg:"min=0,max=10,default=5"`
}
実装
比較結果
- 話に聞く通り reflect は generate (で生成される予定のコードの) 約 60 倍程度遅い
- とはいえ激遅というわけでもないが GAE/Go とかで数十 ns でレスポンス返してる!すごい!とか楽しみたい場合は 180ns が 3ns になるのは嬉しいのでこのまま実装進めてみる。
BenchmarkValidReflect-4 10000000 188 ns/op
BenchmarkValidGenerate-4 500000000 3.33 ns/op