Go言語の構造体にunderscore.js風のメソッドを追加する「gen」を試す

clipperhouse/gen

インストール

$ go get github.com/clipperhouse/gen

コマンドラインツール「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とは異なり、構造体ごとにメソッドを生成するので、キャストをする必要がなくシンプルに使えるのが良い感じ