неожиданный вывод при обходе двоичного дерева

# #go #concurrency #channel

Вопрос:

 func New(k int) *Tree
// New() returns a random binary tree holding the values k, 2k, ..., 10k.
 

Я просто пытаюсь обойти двоичное дерево в goroutine и добавить значения в канал. Затем распечатайте их в главной программе

Код

 func binary(t *tree.Tree, ch chan int) {
    if t != nil {
        binary(t.Left, ch)
        ch <- t.Value
        binary(t.Right, ch)
    }
}

func Walk(t *tree.Tree, ch chan int) {
    defer close(ch)
    binary(t, ch)
}

func main() {
    ch := make(chan int)
    go Walk(tree.New(1), ch)
    for i := range ch {
        fmt.Printf("%d ", <-ch)
        _ = i
    }
}
 

Ожидаемый результат = 1 2 3 4 5 6 7 8 9 10

Результат = 2 4 6 8 10

Ответ №1:

for Оператор с range предложением по каналу получает значения из канала и сохраняет их в переменной цикла.

Это означает i , что переменная будет содержать значения, полученные из ch , которые вам не нужно получать ch .

Тем не менее, вы не используете i , и вы действительно получаете от ch . Таким образом, вы пропустите каждый второй элемент (и вы также рискуете быть заблокированным, если на канале будет нечетное количество элементов).

Сделай это вот так:

 for v := range ch {
    fmt.Printf("%d ", v)
}
 

Ответ №2:

На основе предложения icza:

 func binary(t *tree.Tree, ch chan int) {
    if t != nil {
        binary(t.Left, ch)
        ch <- t.Value
        binary(t.Right, ch)
    }
}

func Walk(t *tree.Tree, ch chan int) {
    defer close(ch)
    binary(t, ch)
}

func main() {
    ch := make(chan int)
    go Walk(tree.New(1), ch)
    for v := range ch {
    fmt.Printf("%d ", v)
    }
}
 

Комментарии:

1. Голосование против, потому что это просто переупаковка существующего ответа (без объяснения причин) и, следовательно, бесполезно.