* Fei Ding <fding...@gmail.com> [160916 23:30]:
> Link here: https://play.golang.org/p/cdryPmyWt5
> 
> The code above is going to check the differences between pointers and 
> values in a for loop, while go statement is also used at the same time. For 
> code:
> 
>     values := []field{{"one"},{"two"},{"three"}}
>     for _, v := range values {
>         go v.print()
>     }
> 
> we know that the console will print *three three three* as result, because 
> for loop runs into its end before go routines start executing, which write 
> *v* as the last element of the slice. But what about pointers? 
> 
>     poniters := []*field{{"one"},{"two"},{"three"}}
>     for _, v := range poniters {
>         go v.print()
>     }
> 
> It seems to print* one two three*, why?

Try running your example with the race detector.  Then try commenting
out, on separate trials, each of the two cases, again running under the
race detector.

The second case runs without a race, but the first does not.

To understand why, you must carefully analyze what is happening
according to the Go specification
(https://golang.org/ref/spec#Go_statements).

In the both cases, the variable v is reused for all iterations of the
for loop; that is, every iteration of the loop uses the same variable v,
but with a different value for each iteration.

Now, in the first case, v is of type field.  The go statement evaluates
the function value and parameters.  Evaluating the function value means,
essentially, getting a pointer to the function to be called (this is a
simplification, but is accurate enough for this analysis); it does not
yet call the function.

A method call can be thought of as a function call with the receiver as
an implied first argument.  So the first, implied, argument is evaluated
as &v (because, according to the spec, x.m() is shorthand for (&x).m()
in this scenario).  The go statement creates a new goroutine with this
particular function call, with the address of v as the first argument,
to be executed at the go scheduler's discretion.

Next, the for loop assigns the next element from the slice values to the
variable v.  This is the data race.  There is no guarantee that the
scheduler will wait for the sleep statement after the loop to start
executing the first goroutine, and in fact it didn't on one run on my
system; I got a result of two three three.  There is no synchronization
between the assignment to v by the for loop and the reference of v.name
in v.print, so you have a data race.

In the second case, v is of type *field.  The go statement evaluates the
first, implied, argument as the current value of v (the first pointer in
the slice).  The go statement creates a goroutine with a call to the
print method with that value as the argument.

When the for loop assigns the next element from the slice to v, it is
not changing anything that is being referenced by the go routine, so
there is no data race (and the values printed are taken from successive
slice elements).

...Marvin

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to