I
I
impressive172020-07-20 23:32:41
go
impressive17, 2020-07-20 23:32:41

Why does an anonymous function only work with the last value of a variable?

There is a code

package main

import (
  "sync"
)

const N = 10

func main() {
  m := make(map[int]int)
      
  wg := &sync.WaitGroup{}
  mu := &sync.Mutex{}
  wg.Add(N)
  for i := 0; i < N; i++ {
                k:= 5
    go func() {
      defer wg.Done()
      mu.Lock()
                       println(i,k)
      m[i] = k
      mu.Unlock()
    }()
  }
  wg.Wait()
  println(len(m))
  println(m[0])

The output shows that here we change only m[10]
I understand that in order to put down values ​​for all indices 0...9, you need to add i as an argument to the anonymous function, but I don’t quite understand why. It is clear if they would save the state and then call these anonymous functions later, getting a closure in essence. But here we are running anonymous functions immediately, and since they have access to the context in which they are called, it seems that i should be different.
What is the focus?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Evgeny Mamonov, 2020-07-20
@impressive17

The bottom line here is that at the moment when the anonymous function starts to execute, the execution of the loop will already end by that moment and i will be equal to 10.
That is, the scheduler does not have time to launch the goroutines, they are actually launched after the loop, but some of them can be in time and run during the loop ...
The easiest way to get the desired result is to pass the value as a parameter

go func(idx int) {
    ...
}(i)

Full example:
package main

import (
    "sync"
)

const N = 10

func main() {
    m := make(map[int]int)
    wg := &sync.WaitGroup{}
    mu := &sync.Mutex{}
    wg.Add(N)
    for i := 0; i < N; i++ {
        k := 5
        go func(idx int) {
            defer wg.Done()
            mu.Lock()
            println(idx, k)
            m[idx] = k
            mu.Unlock()
        }(i)
    }
    wg.Wait()
    println(len(m))
    println(m[0])
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question