ゴルーチンとチャネルを使ってジェネレータを作ることもできる。
package main import ( "fmt" ) type Item interface { Eq(Item) bool Less(Item) bool } type Node struct { item Item left, right *Node } func newNode(x Item) *Node { p := new(Node) p.item = x return p } func insertNode(node *Node, x Item) *Node { switch { case node == nil: return newNode(x) case x.Eq(node.item): return node case x.Less(node.item): node.left = insertNode(node.left, x) default: node.right = insertNode(node.right, x) } return node } func foreachNode(f func(Item), node *Node) { if node != nil { foreachNode(f, node.left) f(node.item) foreachNode(f, node.right) } } type Tree struct { root *Node } func newTree() *Tree { return new(Tree) } func (t *Tree) insertTree(x Item) { t.root = insertNode(t.root, x) } func (t *Tree) foreachTree(f func(Item)) { foreachNode(f, t.root) } func (t *Tree) makeGen() func() Item { ch := make(chan Item) go func() { t.foreachTree(func(x Item) { ch <- x } ) close(ch) }() return func() Item { return <- ch } } type Int int func (n Int) Eq(m Item) bool { return n == m.(Int) } func (n Int) Less(m Item) bool { return n < m.(Int) } func main() { a := newTree() b := []int { 5,6,4,7,3,8,2,9,1,0 } for _, x := range b { a.insertTree(Int(x)) } resume := a.makeGen() for i := 0; i < 11; i++ { fmt.Println(resume()) } }
makeGen
関数は無名関数を返す。この無名関数はクロージャになっていて、makeGen
内のゴルーチンからチャネルを使って受け取った値を返す。ゴルーチンは二分木の値を昇順に返すので、結果として無名関数も呼び出しごとに同じ順で値を返すことになる。
実行してみよう。
^o^ > go run go_gen.go 0 1 2 3 4 5 6 7 8 9 <nil>
最後の <nil>
は何だろう?