Передача указателя внутри цикла с анонимными функциями go вызывает использование только последнего указателя элемента

Поэтому в следующем коде я передаю указатели на анонимные функции go, но код работает не так, как я ожидаю.

package main

import "fmt"

type (
    Element struct{
        Name string
    }
)

func main() {
    elements := []Element{{"first"}, {"second"}, {"third"}, {"fourth"}}
    waiting := make(chan bool)

    for _, element := range elements {
        go func(element *Element){
            fmt.Println("Element Name: ", element.Name)
            waiting <- true
        }(&element)
    }

    for i := 0; i < 4; i++{
        <- waiting
    }
}

Я ожидал, что код напишет:

  • 'первый'
  • "Второй"
  • 'в третьих'
  • "Четвёртый"

в любом порядке, но вместо этого это печать:

  • "Четвёртый"
  • "Четвёртый"
  • "Четвёртый"
  • "Четвёртый"

Таким образом, кажется, что анонимная функция go "разрешает" свой параметр *Element для того, что было в этом цикле в то время, поэтому этот код можно исправить, передав сам Element{} вместо указателя на элемент.

Мой вопрос:

  • Это определенное поведение?
  • Как я могу переписать это, чтобы принять указатели на мой элемент {}?

Детская площадка:

http://play.golang.org/p/tcRvforQE4

Изменить: форматирование вопроса

1 ответ

Решение

Что происходит, так это то, что цикл for помещает значение elements[i] В то же самое element переменная для каждой итерации, не создавая новую. Это означает, что &element всегда один и тот же адрес (попробуйте распечатать его перед вызовом функции!)

Простым решением было бы просто передать ему указатель на фактический член среза:

for i := range elements {

    go func(element *Element){
        fmt.Println("PostStream: ", element.Name)
        waiting <- true
    }(&elements[i])
}
Другие вопросы по тегам