golang 推迟在预期时不评估

标签 go variable-assignment deferred

因此,根据规范,延迟函数中的值在调用延迟函数时进行计算,但直到封闭函数返回时才会执行操作。我明白了,并且理解了整个“for i:=0;i<4;i++ defer example prints 3210”。

但是,当我尝试使用 defer 临时分配覆盖值时(将最大 m 分配给队列长度 q),然后确保在我完成后重置该值(演示的示例已简化):

type tss struct {
    q int
    m int
}

func (t *tss) test() {
    if true {
        defer func() {
            t.q=t.q     //this should evaluate to 't.q = 50' right?
            fmt.Println("assigned",t.q,"to t.q")
        }()
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

func main() {
    ts := tss{50,1}
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
    ts.test()
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
}

我希望收到输出:

q=50, m=1
q=1, m=1
assigned 50 to t.q
q=50, m=1

但实际输出是:

q=50, m=1
q=1, m=1
assigned 1 to t.q
q=1, m=1

因此,似乎在错误的时间评估了这些值。但是,当我首先将 t.q 转储到一个变量中并将该赋值移到延迟函数之外,并将测试函数更改为如下所示时:

func (t *tss) test() {
    if true {
        qtmp := t.q
        defer func() {
            //assigning qtmp here still assigns 1 back to t.q
            t.q=qtmp
            fmt.Println("assigned",t.q,"to t.q")
        }()
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

我得到上面的预期输出,其中分配了 50。

我是不是遇到了错误,还是我遗漏了有关在延迟函数中赋值的内容?

可能需要注意的是,如果我将 t.q 作为函数参数传入,也同样有效:

func (t *tss) test() {
    if true {
        defer func(q int) {
            t.q=q
            fmt.Println("assigned",t.q,"to t.q")
        }(t.q)
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

编辑:这是使用答案中的方法的完整版本:

type tss struct {
    q int
    m int
}

func (t *tss) test() {
    if true {
        defer func(q int) {
            t.q=q     //this will correctly evaluate to 't.q = 50'
            fmt.Println("assigned",t.q,"to t.q")
        }(t.q)
        t.q = t.m
    }
    fmt.Printf("q=%v, m=%v\n", t.q, t.m)
}

func main() {
    ts := tss{50,1}
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
    ts.test()
    fmt.Printf("q=%v, m=%v\n", ts.q, ts.m)
}

和正确的输出:

q=50, m=1
q=1, m=1
assigned 50 to t.q
q=50, m=1

最佳答案

所以我在校对我的帖子时回答了我自己的问题。与其删除它以掩饰我的尴尬,不如将其保留以防其他人遇到同样的困惑。

延迟函数在调用时计算函数的任何 ARGUMENTS。它不会立即计算函数体内的任何值。因此,在延迟操作发生时执行内部分配。

所以:

  1. 代码运行
  2. 遇到延迟语句
  3. golang 存储参数值以备后用
  4. 延迟函数的主体被完全忽略
  5. 其余代码运行到封闭函数的末尾
  6. 使用存储的参数值执行延迟函数

-迈克

关于golang 推迟在预期时不评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28459917/

相关文章:

javascript - 将回调附加到发布

javascript - 延迟链接,Node.js 和 q,所有链部分的一个 ErrorHandler

c - 在c中初始化结构

go - 如何在 http goroutines 之间共享 mysql 连接?

go - 我们可以在 go 中动态创建一个函数吗?

go - 如何动态解析或自检变量

c++ - 为什么 C++ 允许将整数分配给字符串?

c++ - 将派生类分配给基类

javascript - 在 jquery deferred 解析请求数组后总是调用一个 Action

azure - Go SDK for Azure 如何在没有服务主体的情况下创建虚拟机?