ゼロから学ぶGo言語プログラミング(15) A Tour of Go 67~70
A Tour of Goの続き。
67.Selcet
selectは、switchのようで違う、goroutine用の制御構造。
select は、それの case の条件で、いずれかを実行できるようになるまでブロックし、
こうあるので、selectのcaseにはchannelが必須ということでしょうか。
複数のcaseが成立した場合、全てでも先頭でも末尾でもなく、ランダムに実行されるcaseが決まるというのは、使い所があるんでしょうか。
68.Default Selection
これもswitchと同じで、caseとdefaultで制御。
通信のレスポンスとか待機時間やステータスが色々な場合に、selectで待ち構えておいて、defaultで待機処理したりに使えるのかな。
構文の性格上、fallthrough は不要だから無さそう。
69.Exercise: Equivalent Binary Trees
70.Exercise: Equivalent Binary Trees
goroutineのまとめっぽい課題。
"Binary Trees"で、バイナリデータを持ったツリー?と勘違いしてしまったが、二分木のことだった。 ツアーの解説の中では二分木という表現の方が良いと思う。
課題の内容は、"code.google.com/p/go-tour/tree"パッケージによって、二分木を生成するtree.New()が提供され、この二分木を比較して同一かを判定する、というもの。
二分木の比較をするためには、ツリーを辿って探査していかないといけないのか。 Walk関数でそれを実装しろとなっている。 与えられる二分木はこういう構造体。
type Tree struct { Left *Tree Value int Right *Tree }
Treeは自身の持つ値を返す Value()を持ち、LeftやRightは子のTreeへのポインタ。 ということは、ルートから順に値を取り、LeftやRightの存在を確認して、存在すれば次のノードへ、という方法で走査できそう。
Walk()にchannelを渡すのだから、go Walk()という風にgoroutineで動かすのだろうと試すと、"runtime error: invalid memory address or nil pointer dereference"のpanicが。 tにツリーが渡される前提になっていたのが原因だったので、t == nil でWalk()を終了することに。 というようなのを繰り返し、なんとか動く形にはなった。
chaanelでの受信を条件にしたループの書き方が分からなかったけど、rangeでいけるらしい。
他に、Walk()ひとつを呼ぶだけでは、close()のタイミングが持ちようがなく、結局Walk()とwalkNode()という2つの関数を設置した。
package main import ( "code.google.com/p/go-tour/tree" "fmt" ) // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int) { walkNode(t, ch) close(ch) } func walkNode(t *tree.Tree, ch chan int) { if t == nil { return } if t.Left != nil { walkNode(t.Left, ch) } ch <- t.Value if t.Right != nil { walkNode(t.Right, ch) } } // Same determines whether the trees // t1 and t2 contain the same values. func Same(t1, t2 *tree.Tree) bool { c1 := make(chan int) c2 := make(chan int) go Walk(t1, c1) go Walk(t2, c2) for n1 := range c1 { n2 := <-c2 if n1 != n2 { return false } } return true } func main() { fmt.Println(Same(tree.New(1), tree.New(1))) fmt.Println(Same(tree.New(1), tree.New(2))) }
相変わらずこれがGoらしいコードなのか、そして根本的な使い方など誤っていないのかは分からない。 でもとりあえず、goroutineに少しだけ慣れられた気がする。