Пожалуйста, рассмотрите фрагмент https://play.golang.org/p/GnhA1Tgw4sz, Это упрощенная версия проблемы, с которой я столкнулся. Первоначально я пытался отправить UDP-сообщения в пункты назначения в массиве, и я заметил проблемы с равномерным распределением.
Кроме того, код:
package main
import (
"fmt"
"time"
)
var (
dests = [...]string{"word1", "word2", "word3", "word4", "word5", "word6", "word7", "word8"}
)
func main() {
fmt.Println("Hello!")
fmt.Println("dests", dests)
for _, dest := range dests {
fmt.Println("dest is", dest)
go func(dest_ptr *string) {
fmt.Println("Trying", *dest_ptr, dest_ptr)
}(&dest)
}
time.Sleep(200 * time.Second)
}
Когда я бегу,
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Обратите внимание, что я нажимаю word8
все время, вероятно, начиная с &dest
перезаписывается. Я знаю, что у меня не будет этой проблемы без указателей, так как demo'd @ https://play.golang.org/p/ZD9JIuvdypJ.
Я бы хотел использовать указатели, поскольку моя первоначальная проблема требует этого. Как правильно достичь этого?
Исходя из C, это была хорошая проблема! Как я узнал, Go не создает новую переменную для каждой итерации, это может быть исправлено в будущем.
вот два обходных пути:
$ cat fixa.go
package main
import (
"fmt"
"time"
)
var (
dests = [...]string{"word1", "word2", "word3", "word4", "word5", "word6", "word7", "word8"}
)
func main() {
fmt.Println("Hello!")
fmt.Println("dests", dests)
for i := range(dests){
go func(dest_ptr * string){
fmt.Println("Handling", * dest_ptr, dest_ptr)
}(&dests[i])
}
time.Sleep(200 * time.Second)
}
и
$ cat fixb.go
package main
import (
"fmt"
"time"
)
var (
dests = [...]string{"word1", "word2", "word3", "word4", "word5", "word6", "word7", "word8"}
)
func main() {
fmt.Println("Hello!")
fmt.Println("dests", dests)
for _, dest := range dests {
dest := dest // create a new variable, using a declaration style that may seem odd but works fine in Go:
go func(dest_ptr *string) {
fmt.Println("Trying", *dest_ptr, dest_ptr)
}(&dest)
}
time.Sleep(200 * time.Second)
}