立即评估延迟调用的参数

Rud*_*koŭ 4 go deferred

《围棋之旅》中写道:

延迟调用的参数将立即求值,但是直到周围的函数返回后,函数调用才会执行。

我很难理解报价的第一部分。什么叫立即?

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
Run Code Online (Sandbox Code Playgroud)

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

在这里推迟什么,立即评估什么?

icz*_*cza 6

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

每次“延迟”执行语句,函数值和参数来调用评价像往常一样,重新保存,但不会被调用的实际功能。

函数值(其调用被延迟)及其参数均被评估。但是尚未调用延期函数。

让我们以小步骤迭代到您的示例:

defer f("a")
Run Code Online (Sandbox Code Playgroud)

在这种情况下,将评估函数值(将为f),并对参数进行评估,该参数是一个常量,因此将为"a"

下一步:

defer f(g("a"))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,将对函数值进行评估(将为f),并对参数进行评估,这g将使用进行调用"a"(因为g返回值是的参数f)。

下一步:

defer f()()
Run Code Online (Sandbox Code Playgroud)

如果该f函数返回一个函数,则此方法有效。函数值将被评估(这意味着f将被调用!),但其返回值将不被调用,即被推迟。

defer f(g())()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,延迟函数是的返回值f,因此f必须调用评估延迟函数值,并且必须先调用此函数g。的返回值f将被延迟(不调用)。

回到您的示例:

defer def("defered line")()
Run Code Online (Sandbox Code Playgroud)

计算函数值,它是的返回值def,因此def称为。的返回值def将被推迟。它的参数已评估,但实际上没有参数。

因此,从逻辑上讲这是发生的情况:

  1. 评估延迟的函数值,这要求:
    • def 函数必须被调用,这要求:
      • def评估的参数是一个常量:defered line"
  2. 评估延迟函数的参数;由于没有参数,因此此步骤已完成。

如果我们布置以上结构,则会依次发生以下情况:

  • def评估参数:这是一个常数"defered line"
  • def被称为打印tier up及其参数:defered line
  • 的返回值def叫,这是什么推迟。
  • 功能main打印:main
  • 函数main返回,因此现在调用延迟函数。延迟功能打印clean up