无法在for循环中将变量分配给匿名函数 [英] Cannot assign variable to anonymous func in for loop

查看:87
本文介绍了无法在for循环中将变量分配给匿名函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过制定任务计划来学习Go-lang.我使用的 cron库接受cron表达式和func作为添加调度程序的参数.

I'm studying go-lang by developing a task schedular. The cron library I use accepts a cron expression and a func as parameters to add a scheduler.


c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })

我正在开发的计划表根据yaml文件计划作业.因此,我迭代作业以添加时间表,如下所示:

The schedular I am developing schedules jobs according to a yaml file. So I iterate the jobs to add schedulars like this:


type Job struct {
    Name        string
    Interval    string

}

func DistributeJob(job Job) {
    log.Println("running", job, job.Interval)
}

func main() {
    //load config from yaml
    c := cron.New()

    for _, job := range config.Jobs {
        c.AddFunc("@every "+job.Interval, func() {
            DistributeJob(job)
        })
        log.Println("Job " + job.Name + " has been scheduled!")
    }

    c.Start()
    select {}
}

所有作业均按其间隔安排,但事实证明,它们正在打印最后一个作业的描述.例如,如果我计划两个作业,则第一个间隔为3分钟,而后一个间隔为1分钟.控制台将打印:

All jobs are scheduled on their intervals but it turns out that they're printing the last job's description. For example, if I schedule two jobs, the first interval on 3min and the latter interval on 1min. The console prints:


12:01: Running latter 1min
12:02: Running latter 1min
12:03: Running latter 1min
12:03: Running latter 1min//this one should be the first job

我认为问题出在


    func() {
        DistributeJob(job)
    })

似乎只需要最后一份工作,但我不知道为什么.我尝试使用

It seems it only takes the last job but I can't figure out why. I tried using


    c.AddFunc("@every "+job.Interval, func(job JobType) {
        DistributeJob(job)
    }(job))

但由于无法用作值而失败

but it fails due to cannot used as value

推荐答案

虽然您没有使用goroutine,但您犯的错误几乎与此处描述的错误相同:

While you are not using goroutines, the mistake you are making is almost identical to the one described here: https://github.com/golang/go/wiki/CommonMistakes#using-closures-with-goroutines

引用:

上述循环中的val变量实际上是一个采用每个slice元素值的单个变量.因为闭包都只绑定到一个变量,所以很有可能在运行此代码时,您会看到为每次迭代打印的最后一个元素,而不是序列中的每个值,因为goroutine可能直到开始时才开始执行循环之后.

The val variable in the above loop is actually a single variable that takes on the value of each slice element. Because the closures are all only bound to that one variable, there is a very good chance that when you run this code you will see the last element printed for every iteration instead of each value in sequence, because the goroutines will probably not begin executing until after the loop.

因此,您尝试进行的修复(将其作为参数传递给函数)将在原则上解决该问题,但是您无法将具有参数的函数传递给cron库-具有参数的函数与不带(除了添加()之外,您实际上是在预先调用该函数并尝试传递其返回值.)

So your attempted fix (to pass it as a parameter to your function) would in principle fix the problem, however you cannot pass a function with parameters to the cron library - a function with parameters is a different type from one without (in addition to which by adding the () you are actually calling the function in advance and trying to pass its return value).

最简单的解决方法是为循环的每次迭代创建一个新变量,从而避免整个问题,就像这样:

The simplest fix is to create a new variable for every iteration of the loop and avoid the whole problem, like so:

for _, job := range config.Jobs {
    realJob := job // a new variable each time through the loop
    c.AddFunc("@every "+realJob.Interval, func() {
        DistributeJob(realJob)
    })
    log.Println("Job " + realJob.Name + " has been scheduled!")
}

这篇关于无法在for循环中将变量分配给匿名函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆