Range over string slice is inconsistent

269 Views Asked by At

This code:

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)
}

produces the output "c c c", while this code:

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

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

produces the output "[a b c]"

The first one would suggest that for range iterates over references (which it should not), and the second one suggests that it iterates over copies of values (which it should).

Why doesn't the first one produce the output "a b c"?

1

There are 1 best solutions below

0
On

When uses goroutine you must assume that it will running in parallelo. So in this case might occur 'c c c' as too 'b b b' or 'a a a'

On run in 3 times this code:

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

You will send for running 3 times this code:

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

So, might occur of func() start running in t2, per example. In this case the result will 'c c c' because s equals latest value (string_slice[2]).

The solution is copy value by func params:

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

Or create new value per iteration

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

See working in https://play.golang.org/p/uRD6Qy6xSw