Hi everybody,
I’m a new go user and, while doing the go tour, I got stuck with an incomprehensible behaviour, at least for me.
It specifically relate to channel and select behaviour when trying to resolve the tree exercise.
Here is my code :
import (
"fmt"
"golang.org/x/tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
walk(t, ch)
close(ch)
}
func walk(t *tree.Tree, ch chan int) {
if t != nil {
walk(t.Left, ch)
ch <- t.Value
walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
m1, m2 := map[int]bool{}, map[int]bool{}
var ok1, ok2 bool
var v1, v2 int
for {
select {
case v1, ok1 = <-ch1:
if !ok1 {
break
}
m1[v1] = true
case v2, ok2 = <-ch2:
if !ok2 {
break
}
m2[v2] = true
}
if !ok1 && !ok2 {
break
}
}
fmt.Println(m1, m2)
if len(m1) != len(m2) {
return false
}
for k := range m1 {
_, exists := m2[k]
if !exists {
return false
}
}
return true
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
/*for v := range ch {
fmt.Println(v)
}*/
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
Let zoom in a little bit to the part that is confusing me :
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
m1, m2 := map[int]bool{}, map[int]bool{}
var ok1, ok2 bool
var v1, v2 int
for {
select {
case v1, ok1 = <-ch1:
if !ok1 {
break
}
m1[v1] = true
case v2, ok2 = <-ch2:
if !ok2 {
break
}
m2[v2] = true
}
if !ok1 && !ok2 {
break
}
}
fmt.Println(m1, m2)
if len(m1) != len(m2) {
return false
}
for k := range m1 {
_, exists := m2[k]
if !exists {
return false
}
}
return true
}
In this for select, the case that involve ch1 is never treated. Which lead to m1 never being populated and in return the Same function gives a bad result.
My understanding is that select should choose one of those two channels pseudo randomly if both channels are available. But for this code, it only chooses ch2.
If I remove the case with ch2, the map m1 is correctly populated.
So here it is, I’m not exactly sure what’s going on here, if someone could enlight me.
Thanks,
Olivier