ゴルーチンとチャネルを使ってジェネレータを作ることもできる。
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> は何だろう?