Go言語の構造体にunderscore.js風のメソッドを追加する「gen」を試す
インストール
$ go get github.com/clipperhouse/gen
コマンドラインツール「gen」
$ gen Usage: gen [[*]package.TypeName] [-[*]all] [-exported] *package.TypeName # generate funcs for specified struct type; use leading * to specify pointer type (recommended) -all # generate all structs in current directory; use leading * to specify pointer type (recommended); shortcut -a or -*a -exported # only generate exported structs; shortcut -e -force # force generate, overriding errors; shortcut -f Examples: gen -*models.Movie # generates funcs for Movie type in the models package; generated Movies type is []*Movie gen -models.Movie # generates funcs for Movie type; generated Movies type is []Movie gen -*all # generates funcs for all struct types in current directory, as pointers gen -all # generates funcs for all struct types in current directory, as values gen -*a -e # generates funcs for all exported struct types in current directory, as pointers
使ってみる
適当なディレクトリにmain.goを用意して、型を用意。
SelectやAverageなど、一部のメソッドを使うためにタグを書いておく必要がある。
package main type Person struct { Name string `gen:"Select"` Age int `gen:"Average,Sum"` } func main() { }
作成したディレクトリにcdしてgenを実行
$ gen main.Person generated main.Persons, yay!
するとperson_gen.goファイルが作成され、Persons型(Personのスライス)に、AllやAnyなどの様々なメソッドが用意される。
person_gen.go
// gen main.Person // this file was auto-generated using github.com/clipperhouse/gen // Mon, 13 Jan 2014 05:26:10 UTC // Sort functions are a modification of http://golang.org/pkg/sort/#Sort // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main import ( "errors" ) // The plural (slice) type of Person, for use with gen methods below. Use this type where you would use []Person. (This is required because slices cannot be method receivers.) type Persons []Person // Tests that all elements of Persons return true for the passed func. See: http://clipperhouse.github.io/gen/#All func (rcv Persons) All(fn func(Person) bool) bool { for _, v := range rcv { if !fn(v) { return false } } return true } // 以下省略...
用意されたメソッドを使ってみる
package main import "fmt" type Person struct { Name string `gen:"Select"` Age int `gen:"Average,Sum"` } func main() { // データ用意 clara := Person{"Clara", 14} tim := Person{"Tim B.", 21} jeremy := Person{"Jeremy", 12} julia := Person{"Julia", 18} emma := Person{"Emma", 20} people := Persons{clara, tim, jeremy, julia, emma} // 18以上のPersonの名前を取得 names := people.Where(func(p Person) bool { return p.Age >= 18 }).SelectName() fmt.Println(names) // [Tim B. Julia Emma] // 年齢の平均 ave, err := people.AverageAge() if err != nil { panic(err) } fmt.Println(ave) // 17 // 年齢の合計 sum := people.SumAge() fmt.Println(sum) // 85 // 年齢でソート byAge := func(a, b Person) bool { return a.Age < b.Age } fmt.Println(people.Sort(byAge)) // [{Jeremy 12} {Clara 14} {Julia 18} {Emma 20} {Tim B. 21}] }
他にもいろいろ用意されている。
gen - a generics library for Go
以前試したgo-linqとは異なり、構造体ごとにメソッドを生成するので、キャストをする必要がなくシンプルに使えるのが良い感じ