Home > Backend Development > Golang > Why Does This Go Code Print 'Three' Three Times Instead of 'One', 'Two', and 'Three'?

Why Does This Go Code Print 'Three' Three Times Instead of 'One', 'Two', and 'Three'?

DDD
Release: 2024-12-09 13:41:11
Original
1017 people have browsed it

Why Does This Go Code Print

Goroutine Behavior: Solving the Mystery

We stumble upon a perplexing behavior in the provided Go code:

package main

import (
    "fmt"
    "time"
)

type field struct {
    name string
}

func (p *field) print() {
    fmt.Println(p.name)
}

func main() {
    data := []field{{"one"}, {"two"}, {"three"}}
    for _, v := range data {
        go v.print()
    }
    <-time.After(1 * time.Second)
}
Copy after login

The question arises: why does this code consistently print "three" three times, instead of displaying "one", "two", and "three" in any order?

Understanding the Issue

The crux of the issue lies in a subtle race condition caused by the use of the range variable v in the goroutine function.

When we write v.print(), we are effectively passing a pointer to the variable v, which is a reference to the current element in the range data loop. However, the loop continues to iterate, modifying the value of v.

When the goroutine executes, it happens to have the final value of v, which is "three". This produces the unexpected output of three "three"s.

Fixing the Problem: Multiple Approaches

There are several ways to resolve this issue:

1. Using a Short Variable Declaration:

Create a new variable v scoped to each iteration of the loop:

for _, v := range data {
    v := v // Short variable declaration to create a new `v`.
    go v.print()
}
Copy after login

2. Using a Slice of Pointers:

Change the type of data to a slice of pointers and pass the individual pointers to the goroutine function:

data := []*field{{"one"}, {"two"}, {"three"}} // Note the '*'
for _, v := range data {
    go v.print()
}
Copy after login

3. Using the Address of Slice Element:

Take the address of each slice element and pass the pointer to the goroutine function:

data := []*field{{"one"}, {"two"}, {"three"}} // Note the '*'
for i := range data {
    v := &data[i]
    go v.print()
}
Copy after login

Conclusion

Remember that taking addresses of range variables can lead to unexpected behavior in goroutines if the loop modifies the value of the variables. By using the techniques outlined above, we can ensure that each goroutine receives a unique value and avoid data race issues.

The above is the detailed content of Why Does This Go Code Print 'Three' Three Times Instead of 'One', 'Two', and 'Three'?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template