43
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-07-17

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.go
type Thing struct {}

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

thing_gen.go
type Things []Thing

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

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

超素敵ですね!

インストール

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

$ go get github.com/clipperhouse/gen

使い方

基本

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

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

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

$ gen

するとmytype_gen.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を使って下さい。
作成されるメソッドは公式ページを見れば大体わかります。

参照型

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

myType.go
// +gen *
type MyType struct {}
*mytype_gen.go
type MyTypes []*MyType

Projections tag

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

myType.go

// +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ではSetListRingのデータ構造を自動生成できます。

myType.go
// +gen containers:"Set,List,Ring"
type MyType struct {}
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も有ります。

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

43
45
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?