Friday, May 17, 2024
HomeGolangLoop variable not captured by goroutines - Getting Assist

Loop variable not captured by goroutines – Getting Assist


Why does this fail (all the time prints 3)

func fundamental() {

	for i := 0; i < 3; i++ {
		go func() {
			fmt.Println(i)
		}()
	}

	time.Sleep(1 * time.Second)
}

whereas this works?

func fundamental() {

	for i := 0; i < 3; i++ {
		func() {
			go fmt.Println(i)
		}()
	}

	time.Sleep(1 * time.Second)
}

As a result of on the time the go routines are scheduled, i is 3.

If you wish to use outer values in a goroutine, cross them when creating the goroutine:

func fundamental() {

	for i := 0; i < 3; i++ {
		go func(i int) {
			fmt.Println(i)
		}(i)
	}

	time.Sleep(1 * time.Second)
}

Extra information
https://eli.thegreenplace.web/2019/go-internals-capturing-loop-variables-in-closures/

You should utilize go vet to keep away from this points

Or go lint (consists of go vet)

Go 1.21 will embrace an experimental setting to alter the loop variable habits. It solves this drawback in addition to related loop issues outdoors goroutine context that embrace, in a method or one other, delayed analysis of the captured loop variable.

The setting is experimental (that’s, it have to be enabled manually), as a result of the Go staff is extraordinarily cautious about language adjustments which may break current Go code.

The Go staff is extraordinarily cautious about language adjustments that would injury current Go code, therefore the setting is experimental (i.e., it have to be activated manually).

The Go staff is extraordinarily cautious about language adjustments that would injury current Go code, therefore the setting is experimental (i.e., it have to be activated manually).

that is anticipated habits, each different language with threading that may use a closure kind perform works this very same means.

you both must seize the state contained in the closure. one of the best and least stunning means is with an argument to the perform. the opposite means is delicate and might be missed by even folks skilled with the language by simply assigning a variable within the native scope to the worth on the time the occasion of the perform is created, more often than not you see this accomplished within the worst means potential; variable shadowing, which in your case would seem like. “intelligent” programmers use the “shorthand” implicit model that catches newbies and even themselves out later when they’re studying the code.

func() {
    i := i
    go fmt.Println(i)
}()

an express perform argument is one of the simplest ways to convey the semantic that’s required.

func(i int) {
	go fmt.Println(i)
}(i)

This is perhaps true, however then, it’s anticipated habits solely to those that understand how different languages with threading work.

Many newcomers come across that habits and would regard the aforementioned loopvar experiment as extra logical than the present habits.

To all of the solutions given, I believe we now have made clear why the primary case does not work.

What I’m lacking (however maybe has been by some means answered) is why the second case, i.e

func fundamental() {

	for i := 0; i < 3; i++ {
		func() {
			go fmt.Println(i)
		}()
	}

	time.Sleep(1 * time.Second)
}

does work.

Right here we don’t use an area scope variable nor will we use an argument to the nameless perform utilized by the loop.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments