Неправильно1 (): go func() { print(v) }()
Go: Часто задаваемые вопросы (FAQ)
Что происходитс замыканиями, выполняемыми как goroutines?
Может возникнуть некоторая путаница при использовании замыканий с параллелизмом.Рассмотрим следующую программу:
func main() {
done := make(chan bool)
values := []string{"a", "b", "c"}
for _, v := range values {
go func() {
fmt.Println(v)
done <- true
}()
}
// wait for all goroutines to complete before exiting
for _ = range values {
<-done
}
}
Можно ошибочно ожидать, что a, b, c будет выводом.Вместо этого вы, вероятно, увидите c, c, c.Это связано с тем, что каждая итерация цикла использует один и тот же экземпляр переменной v, поэтому каждое замыкание совместно использует эту единственную переменную.Когда выполняется замыкание, оно печатает значение v во время выполнения fmt.Println, но, возможно, v изменилось с момента запуска программы.
Чтобы связать текущее значение v с каждым замыканием, как онозапускается, необходимо изменить внутренний цикл для создания новой переменной на каждой итерации.Один из способов - передать переменную в качестве аргумента закрытию:
for _, v := range values {
go func(u string) {
fmt.Println(u)
done <- true
}(v)
}
В этом примере значение v передается в качестве аргумента анонимной функции.Затем это значение доступно внутри функции как переменная u.
Еще проще просто создать новую переменную, используя стиль объявления, который может показаться странным, но прекрасно работает в Go:
for _, v := range values {
v := v // create a new 'v'.
go func() {
fmt.Println(v)
done <- true
}()
}
Ваш wrong1
пример,
for _, v := range data {
go func() {
print(v)
}()
}
Детская площадка: https://play.golang.org/p/0w86nvVMt1g
Выход:
three
three
three
Ваш wrong1
пример, создание новой переменной,
for _, v := range data {
v := v
go func() {
print(v)
}()
}
Детская площадка: https://play.golang.org/p/z5RCI0ZZU8Z
Вывод:
one
two
three
Ваш wrong1
пример, прохождениепеременная в качестве аргумента,
for _, v := range data {
go func(v *field) {
print(v)
}(v)
}
Детская площадка: https://play.golang.org/p/1JVI7XYSqvv
Выход:
one
two
three
fix1 (): go print(v)
Спецификация языка программирования Go
Вызовы
С учетом выражения f типа функции F,
f(a1, a2, … an)
вызывает f с аргументами a1, a2,… an.За исключением одного особого случая, аргументы должны быть однозначными выражениями, присваиваемыми типам параметров F и оцениваться перед вызовом функции.
Операторы Go
Значение функции и параметры оцениваются как обычно в вызывающей программе.
Ваш пример fix1
, оценивающий значение v
до вызова функции,
for _, v := range data {
go print(v)
}
Детская площадка: https://play.golang.org/p/rN3UNaGi-ge
Выход:
one
two
three