Fix for-range Issue Again in Go 1.22

  sonic0002        2024-11-21 01:03:04       1,054        1          English  中文  Tiếng Việt 

With the release of Go 1.22, the Go team addressed a long-standing issue with the for-range loop variable scoping, which had been a common pitfall for developers writing concurrent code. Specifically, the problem was that the loop variable in a for-range loop was reused across iterations, leading to unexpected behavior when closures were involved.

The Issue Before Go 1.22

Consider the following example:

package forange

import "fmt"

func Do() {
    done := make(chan bool)
    values := []string{"a", "b", "c"}

    for _, v := range values {
        go func() {
            fmt.Println(v) // Prints unexpected values
            done <- true
        }()
    }

    for _ = range values {
        <-done
    }
}

And there is a go.mod file as below

module playground

go 1.16

require github.com/ozgio/strutil v0.4.0

In versions of Go prior to 1.22, running this code often resulted in printing the same value (e.g., c) multiple times instead of printing each value in values (a, b, c) as expected. This was because the loop variable v was reused across iterations, and the goroutines captured the same memory address.

The Go 1.22 Fix

Go 1.22 introduced a fix to this behavior by making the loop variable behave as if it were declared fresh in each iteration. This means each closure should now correctly capture the value of v for its corresponding iteration.

However, if you’ve upgraded to Go 1.22 and still observe the old, problematic behavior, the culprit might be your go.mod file. The fix only takes effect if the go.mod file specifies a Go version of 1.22 or higher. This dependency is intentional and allows developers to retain backward compatibility with older behaviors if needed.

With go 1.22 specified in your go.mod and the fix applied, running the above program should correctly print a, b, c. Each goroutine now captures the proper value of v for its iteration.

Lessons Learned

  • Stay Updated: Always read the release notes for new Go versions. The Go 1.22 release notes specifically mention this change and its dependency on go.mod.
  • Use Correct go.mod Versioning: Many Go language features are tied to the go version in go.mod. If you’re relying on new features or fixes, ensure the correct version is specified.
  • Test Thoroughly: Even after upgrading Go, ensure that your programs behave as expected by running comprehensive tests.

Why Is This Dependency Necessary?

The go.mod versioning approach allows teams to adopt fixes incrementally without breaking existing builds. By coupling new language behavior to the go version in go.mod, the Go team ensures backward compatibility while enabling smoother migrations for developers.

If you’ve experienced similar challenges or have insights on how this has impacted your workflow, feel free to share in the comments!

BUG  GO  FOR RANGE  GO.MOD  GO 1.22 

       

  RELATED


  1 COMMENT


xieyonglin [Reply]@ 2024-11-21 06:43:57

Nice article?



  RANDOM FUN

Breakpoint