递归前序遍历,重点保证信道是在递归完后再关闭,因此 close(ch) 必须和递归放在同一个协程内(同步代码块)。
for range 自动停止读取信道。如果不用 range,需要取值时手动判断信道是否关闭,适时 break。
如果信道一直没关闭导致阻塞到其他所有的 go routine 都阻塞或结束了,会报一个deadlock 的错误。如果信道在读取完闭前关闭,会 panic。
package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int) {
if t.Left != nil {
Walk(t.Left, ch)
}
ch <- t.Value
if t.Right != nil {
Walk(t.Right, ch)
}
}
// Same 检测树 t1 和 t2 是否含有相同的值。
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go func(){
Walk(t1, ch1)
close(ch1) // 必须递归完再 close
}()
go func(){
Walk(t2, ch2)
close(ch2)
}()
for i := range ch1 { // for 循环到close(ch1)
if i != <- ch2 {
return false
}
}
return true
}
func main() {
t1 := tree.New(1)
t2 := tree.New(2)
fmt.Print(Same(t1, t1)," end\n")
fmt.Print(Same(t1, t2)," end\n")
}