dongmufen8105 2016-09-16 17:57
浏览 44
已采纳

Go封包捕获规则与defer有何区别?

The following Go code demonstrates a distinction in the closure-capture rules between defer and go closures. In a tutorial, I was told that for-loop variables have scope limited to the loop body, but something seems different here.

package main

import "fmt"

func deferred() {
    for i := 0; i < 5; i++ {
        defer fmt.Println(i)
    }
}

func cps() {
    clo := new(func())
    *clo = func() {}
    defer func() { (*clo)() }()
    for i := 0; i < 5; i++ {
        oldClo := *clo
        *clo = func() {
            fmt.Println(i)
            oldClo()
        }
    }
}

func cpsCpy() {
    clo := new(func())
    *clo = func() {}
    defer func() { (*clo)() }()
    for i := 0; i < 5; i++ {
        oldClo := *clo
        cpy := i
        *clo = func() {
            fmt.Println(cpy)
            oldClo()
        }
    }
}

func main() {
    fmt.Println("defer")
    deferred()
    fmt.Println("cps")
    cps()
    fmt.Println("cpsCpy")
    cpsCpy()
}

This produces output:

defer
4
3
2
1
0
cps
5
5
5
5
5
cpsCpy
4
3
2
1
0

If the difference is intentional, then what are the different use-cases that justify it?

  • 写回答

1条回答 默认 最新

  • duankang5882 2016-09-16 18:20
    关注

    The spec for defer is clear on this. The spec in general is crucial reading for anyone who cares about stuff like variable capture rules, and relatively short for what it is. What it says here is:

    Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.

    It's also covered in the blog post on defer, panic, and recover.

    It's always hard to justify design decisions to everyone's satisfaction, and the defer one in particular does surprise people now and then, notably when you do defer f1(f2(x)) and forget f2(x) will be evaluated immediately.

    One thing that may help remember it, though, is that what comes after defer (or go) is a function call, and just the function invocation itself (not even evaluation of params) is shifted in time. The closure defines a block of code, and accessing the variables happens when the code is executed.


    Since you were curious about the use for the kind of variable capture you get with closures, one example of where it's useful is if you're using a closure with a method like ForEach:

    myBTree.ForEach(func (key, value []byte) {
        //...
    })
    

    It's nice if, like in a regular for loop, the code between the braces can modify variables in the outer scope. That requires that the closure be accessing the variables, not just their values as of a specific time.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog
  • ¥15 Excel发现不可读取的内容
  • ¥15 关于#stm32#的问题:CANOpen的PDO同步传输问题