ゴルーチンとチャネルでジェネレータ

ゴルーチンとチャネルを使ってジェネレータを作ることもできる。

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> は何だろう?