Goで自作型からunderscore.jsやLinqライクなライブラリを作成するgenが便利


Goを書くのはだいたいGAE/Goです。大橋です。
Goは標準ライブラリが豊富なのですが、意外とsliceや配列の細かい処理はもりもり書く必要があったりして、
汎用的なライブラリが欲しいなーと思いつつも、結構面倒のだろうな−という印象がありました。

また昨今の関数型プログラミングの煽りもあり、配列などの処理はeachやsortを流れるように書きたいところです。

そこで使えるのがGo用の関数型プログラミング補助ライブラリジェネレータ[gen](http://clipperhouse.github.io/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を付けそれベースでコードが作成されます。

例えば

```go:type.go
type Thing struct {}
```

のような型があった時genは

```go:thing_gen.go
type Things []Thing
```

といくつかのメソッドを作成します。
そして以下のように使うことができます。

```
myThings := Things{...}
otherThings := myThings.Where(func).SortBy(func)
```

超素敵ですね！

## インストール

いつもどおり`go get`してください

```bash
$ go get github.com/clipperhouse/gen
```

## 使い方

### 基本

genを使うには自作型に対して、まずtagを付けます。

```go:myType.go
// +gen
type MyType struct {
  //...
}
```

そしてこのファイルが有るディレクトリで、genコマンドを実行します。

```bash
$ gen
```

すると`mytype_gen.go`が作成されます。

```go: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を使って下さい。
作成されるメソッドは[公式ページ](http://clipperhouse.github.io/gen/)を見れば大体わかります。

### 参照型 

参照型(?)にしたい場合は `+gen *`のようにします。

```go:myType.go
// +gen *
type MyType struct {}
```

```go:*mytype_gen.go
type MyTypes []*MyType
```

### Projections tag

`Select`や`GroupBy`等のProjection Method(射影?)を利用する場合は、
`projections`タグを追加します。

```go:myType.go

// +gen * projectoins:"int,string"
type MyType struct {
  Name string
  Score int
}
```

するとmyTypesには`SelectString`,`SelectInt`等のメソッドが追加されます。

```go

myTypes := MyTypes{...}

names := myTypes.SelectString(func(t *MyType) string { return t.Name})

// => ["Hoge", "Fuga"]

```

### Containers

genは通常配列の型を作成しますが、`containers`タグを利用することで配列以外のデータ構造も作成できるようになります。

genでは`Set`、`List`、`Ring`のデータ構造を自動生成できます。

```go:myType.go
// +gen containers:"Set,List,Ring"
type MyType struct {}
```

```go:mytype_container.go
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も有ります。

http://ahmetalpbalkan.github.io/go-linq/

ただキャストとか必要なので個人的にはgenのほうが好きだったりします。