立即评估延迟调用的参数

The deferred call's arguments are evaluated immediately

A Tour of Go中写着:

The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.

我无法理解引用的第一部分。什么叫立马?

func def(s string) func() {
    fmt.Println("tier up")
    fmt.Println(s)
    return func(){ fmt.Println("clean up") }
}

func main() {
    defer def("defered line")()
    fmt.Println("main")
}

//Output:
//tier up
//defered line
//main
//clean up

https://play.golang.org/p/Av3mAEXxA4R

这里延迟什么,立即计算什么?

The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.

上面的句子意味着延迟的函数参数在它们被延迟的那一行被评估,但是函数将 运行 在周围的函数之后 main returns.

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.

延迟函数调用在周围函数 returns 之后以后进先出的顺序执行。

延迟函数可以读取并分配给 returning 函数的命名 return 值。

上面这行写的很清楚,就是将return值传给main函数

例如:-

func c() (i int) {
    defer func() { i++ }()
    return 1
}

以上函数将 return 2 值而不是 1。这就是为什么这一行

return func(){ fmt.Println("clean up") }

会在最后调用。

有关延迟的更多信息。 Please read golang blog for defer

defer def("defered line")()

def("defered line")() 是立即评估的延迟调用的参数。

def("defered line") 的计算结果为 func(){ fmt.Println("clean up") },但有副作用。

如果您将传递给 def(string) 的参数从字符串文字(在编译时计算)更改为更有趣的东西,会更清楚,例如:

func bar(s sting) string {
    return s + " bar "
}

func main() {
    defer def(bar(os.Args[1]) + "defered line")()
    fmt.Println("main")
}

defer def(bar(os.Args[1]) + "defered line")()语句 被执行,def 的参数将被完全评估, 这意味着调用 bar 将第一个命令行传递给它 运行 宁您的程序时用户提供的参数, 取 bar 返回的任何内容并附加 它的字符串文字。

然后保存生成的字符串,并将传递给 def 什么时候 运行.

要了解延迟和评估的工作原理,首先让我们看一下 Spec: defer statements:

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.

函数值(其调用被延迟)及其参数都被评估。但是延迟函数还没有被调用。

让我们逐步迭代您的示例:

defer f("a")

在这种情况下,函数值被评估(将是 f),并且参数被评估,这是一个常数,所以它将是 "a"

下一步:

defer f(g("a"))

在这种情况下,函数值被评估(将是 f),并且参数被评估,这意味着 g 将被调用 "a"(因为 g 的 return 值是 f).

的参数

下一步:

defer f()()

如果 f 函数 return 是一个函数,则这是有效的。函数值将被评估(这意味着 f 将被调用!)但其 return 值将不会被调用,这将被推迟。

defer f(g())()

在这种情况下,延迟函数是 f 的 return 值,因此要评估延迟函数值,必须调用 f,并执行此操作 g 必须先调用。 f 的 return 值将被延迟(不调用)。

回到你的例子:

defer def("defered line")()

函数值求值,是def的return值,所以调用defdef 的 return 值将被推迟。它的参数被评估,但实际上它没有参数。

所以逻辑上是这样的:

  1. 计算延迟函数值,这需要:
      必须调用
    • def 函数,这需要:
      • def 的参数被评估,它是一个常量:“defered line"
  2. 评估延迟函数的参数;由于没有参数,这一步就完成了。

如果我们布置上述结构,顺序会发生这种情况:

  • def 的参数被评估:它是一个常量 "defered line"
  • 调用
  • def 打印 tier up 及其参数:defered line
  • def 的 return 值 不是 调用的,这就是延迟的。
  • 函数main打印:main
  • 函数main returns,所以现在调用延迟函数。延迟函数打印 clean up