Goを書くのはだいたいGAE/Goです。大橋です。
Goは標準ライブラリが豊富なのですが、意外とsliceや配列の細かい処理はもりもり書く必要があったりして、
汎用的なライブラリが欲しいなーと思いつつも、結構面倒のだろうな−という印象がありました。
また昨今の関数型プログラミングの煽りもあり、配列などの処理はeachやsortを流れるように書きたいところです。
そこで使えるのがGo用の関数型プログラミング補助ライブラリジェネレータgenです。
genとは
genは以下のように説明されています。
gen is an attempt to bring some generics-like functionality to Go, with inspiration from C#’s Linq, JavaScript’s Array methods and the underscore library. Operations include filtering, grouping, sorting and more.
The pattern is to pass func’s as you would pass lambdas in Linq or functions in JavaScript.
※公式より抜粋
generics-likeが若干訳せないのですが、要はLinqやunderscoreに影響を受けた関数型プログラミング補助ライブラリジェネレータらしいです。
コンセプト
genはCLIを利用して自作型用のコードを作成するジェネレータで、gen自体をimport
することはありません。また他の依存を作ることもありません。
自作型に対してtagを付けそれベースでコードが作成されます。
例えば
type Thing struct {}
のような型があった時genは
type Things []Thing
といくつかのメソッドを作成します。
そして以下のように使うことができます。
myThings := Things{...}
otherThings := myThings.Where(func).SortBy(func)
超素敵ですね!
インストール
いつもどおりgo get
してください
$ go get github.com/clipperhouse/gen
使い方
基本
genを使うには自作型に対して、まずtagを付けます。
// +gen
type MyType struct {
//...
}
そしてこのファイルが有るディレクトリで、genコマンドを実行します。
$ gen
するとmytype_gen.go
が作成されます。
package main
import (
"errors"
)
// Words is a slice of type MyType. Use it where you would use []MyType.
type MyTypes [] MyType
//以降作成されたメソッド群
あとはいい感じでMyTypesを使って下さい。
作成されるメソッドは公式ページを見れば大体わかります。
参照型
参照型(?)にしたい場合は +gen *
のようにします。
// +gen *
type MyType struct {}
type MyTypes []*MyType
Projections tag
Select
やGroupBy
等のProjection Method(射影?)を利用する場合は、
projections
タグを追加します。
// +gen * projectoins:"int,string"
type MyType struct {
Name string
Score int
}
するとmyTypesにはSelectString
,SelectInt
等のメソッドが追加されます。
myTypes := MyTypes{...}
names := myTypes.SelectString(func(t *MyType) string { return t.Name})
// => ["Hoge", "Fuga"]
Containers
genは通常配列の型を作成しますが、containers
タグを利用することで配列以外のデータ構造も作成できるようになります。
genではSet
、List
、Ring
のデータ構造を自動生成できます。
// +gen containers:"Set,List,Ring"
type MyType struct {}
package main
// The primary type that represents a set
type MyTypeSet map[MyType]struct{}
...
// MyTypeList represents a doubly linked list.
// The zero value for MyTypeList is an empty list ready to use.
type MyTypeList struct {
root MyTypeElement // sentinel list element, only &root, root.prev, and root.next are used
len int // current list length excluding (this) sentinel element
}
...
// A Ring is an element of a circular list, or ring.
// Rings do not have a beginning or end; a pointer to any ring element
// serves as reference to the entire ring. Empty rings are represented
// as nil Ring pointers. The zero value for a Ring is a one-element
// ring with a nil Value.
//
type MyTypeRing struct {
next, prev *MyTypeRing
Value MyType // for use by client; untouched by this library
}
...
まとめ
genはGoのソースコードをgo/parser
パッケージを利用してASTとして解析し、コードの作成をしています。
あまりGoのソースコードジェネレータって見たことがなかったのと、
Annotationのような仕組がないのでうーんと思っていたのですが
確かにtagとそもそもパースしてしまえばってのは一つの解な気がします。
こういう感じのなんか作ってみたいですね
ちなみにgoでLinqライクなものを使いたいのであればgo-linqも有ります。
ただキャストとか必要なので個人的にはgenのほうが好きだったりします。