在for each循环中使用go例程时,func literal捕获go vet range变量

在for each循环中使用go例程时,func literal捕获go vet range变量,go,Go,我不确定什么是“func literal”,因此这个错误让我有点困惑。我想我看到了这个问题——我在一个新的go例程中引用了一个范围值变量,因此该值可能随时发生变化,而不是我们所期望的。解决这个问题的最好办法是什么 有关守则: func (l *Loader) StartAsynchronous() []LoaderProcess { for _, currentProcess := range l.processes { cmd := exec.Command(curre

我不确定什么是“func literal”,因此这个错误让我有点困惑。我想我看到了这个问题——我在一个新的go例程中引用了一个范围值变量,因此该值可能随时发生变化,而不是我们所期望的。解决这个问题的最好办法是什么

有关守则:

func (l *Loader) StartAsynchronous() []LoaderProcess {
    for _, currentProcess := range l.processes {
        cmd := exec.Command(currentProcess.Command, currentProcess.Arguments...)
        log.LogMessage("Asynchronously executing LoaderProcess: %+v", currentProcess)
        go func() {
            output, err := cmd.CombinedOutput()
            if err != nil {
                log.LogMessage("LoaderProcess exited with error status: %+v\n %v", currentProcess, err.Error())
            } else {
                log.LogMessage("LoaderProcess exited successfully: %+v", currentProcess)
                currentProcess.Log.LogMessage(string(output))
            }
            time.Sleep(time.Second * TIME_BETWEEN_SUCCESSIVE_ITERATIONS)
        }()
    }
    return l.processes
}
我建议的解决方案:

func (l *Loader) StartAsynchronous() []LoaderProcess {
    for _, currentProcess := range l.processes {
        cmd := exec.Command(currentProcess.Command, currentProcess.Arguments...)
        log.LogMessage("Asynchronously executing LoaderProcess: %+v", currentProcess)
        localProcess := currentProcess
        go func() {
            output, err := cmd.CombinedOutput()
            if err != nil {
                log.LogMessage("LoaderProcess exited with error status: %+v\n %v", localProcess, err.Error())
            } else {
                log.LogMessage("LoaderProcess exited successfully: %+v", localProcess)
                localProcess.Log.LogMessage(string(output))
            }
            time.Sleep(time.Second * TIME_BETWEEN_SUCCESSIVE_ITERATIONS)
        }()
    }
    return l.processes
} 

但这真的解决了问题吗?我刚刚将引用从范围变量移动到另一个局部变量,该局部变量的值基于我所处的for each循环的迭代。

是的,您所做的是正确修复此警告的最简单方法


在修复之前,只有一个变量,所有goroutine都引用它。这意味着他们看不到启动时的值,而是当前值。在大多数情况下,这是该范围内的最后一个进程。

别难过,这是围棋新手的常见错误,是的,varcurrentProcess会为每个循环更改,因此您的goroutines将使用slice l中的最后一个进程。进程,您只需将变量作为参数传递给匿名函数,像这样:

func (l *Loader) StartAsynchronous() []LoaderProcess {

    for ix := range l.processes {

        go func(currentProcess *LoaderProcess) {

            cmd := exec.Command(currentProcess.Command, currentProcess.Arguments...)
            log.LogMessage("Asynchronously executing LoaderProcess: %+v", currentProcess)

            output, err := cmd.CombinedOutput()
            if err != nil {
                log.LogMessage("LoaderProcess exited with error status: %+v\n %v", currentProcess, err.Error())
            } else {
                log.LogMessage("LoaderProcess exited successfully: %+v", currentProcess)
                currentProcess.Log.LogMessage(string(output))
            }

            time.Sleep(time.Second * TIME_BETWEEN_SUCCESSIVE_ITERATIONS)

        }(&l.processes[ix]) // passing the current process using index

    }

    return l.processes
}

对于那些寻求更简单示例的人:

这是错误的:

func main() {
  for i:=0; i<10; i++{
    go func(){
        processValue(i)
    }()
  }
}

func processValue(i int){
  fmt.Println(i)
}
func main() {
  for i:=0; i<10; i++{
    go func(differentI int){
        processValue(differentI)
    }(i)
  }
}

func processValue(i int){
  fmt.Println(i)
}
func main(){

对于i:=0;i如果您有使用JS中Javascript和闭包的经验,那么很容易将其与for循环中的setTimeout的经典示例进行比较,并在迭代结束时使用循环变量的最终值进行setTimeout。

感谢更新后的代码,它看起来很棒!我的代码中有一个非常严重的错误,需要呃,一个小时的修复工作与类似的事情有关。我回来了[]*LoaderProcess之前没有意识到一个片已经是指针,所以我实际上返回了一个片指针,其中每个指针指向同一个LoaderProcess实例,而该实例恰好是最后一个完成的命令。每次执行后都不一样。因此,从一段代码中学到了两个重要的教训。谢谢。我们是否要使用索引发送吗?太棒了,谢谢。您能确认func literal只是一个内嵌定义的函数吗?比如内嵌go例程所需的函数吗?