Диапазон по фрагменту строки не согласован

Этот код:

import "fmt"
import "time"
func main() {
    string_slice:=[]string{"a","b","c"}

    for _,s:=range string_slice{
        go func(){
            time.Sleep(1*time.Second)
            fmt.Println(s)
        }()
    }

    time.Sleep(3*time.Second)
}

производит вывод "c c c", в то время как этот код:

import "fmt"
func main() {
    string_slice:=[]string{"a","b","c"}

    for _,s:=range string_slice{
        s="asd"
        fmt.Println(s)
    }
    fmt.Println(string_slice)
}

производит вывод "[a b c]"

Первый предполагает, что для диапазона выполняется итерация по ссылкам (чего не следует), а второй предполагает, что он выполняет итерации по копиям значений (что и следует).

Почему первый не выдает "a b c"?

1 ответ

Когда вы используете goroutine, вы должны предполагать, что он будет работать в параллель. Таким образом, в этом случае может произойти "CCC", как слишком "BBB" или "Aa A"

При запуске в 3 раза этот код:

for _,s:=range string_slice \\run t0, t1, t2 

Вы отправите для запуска 3 раза этот код:

go func(){
  fmt.Println(s)
}()//send in t0, t1, t2

Таким образом, может произойти запуск func() в t2, например. В этом случае результатом будет 'ccc', потому что s равно последнему значению (string_slice[2]).

Решение - копировать значение с помощью func params:

for _, s := range string_slice{
    go func(x string){
        time.Sleep(1*time.Second)
        fmt.Println(x)
    }(s)
}

Или создайте новое значение для каждой итерации

//creating new value per iteration
for i := range string_slice{
    s := string_slice[i]
    go func(){
        time.Sleep(1*time.Second)
        fmt.Println(s)
    }()
}

Смотрите работу в https://play.golang.org/p/uRD6Qy6xSw

Другие вопросы по тегам