立即评估延迟调用的参数

时间:2018-07-16 10:58:47

标签: go deferred

A Tour of Go中写道:

  

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

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

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

这里延迟什么,立即评估什么?

4 个答案:

答案 0 :(得分:5)

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

  

每次执行“ defer”语句时,调用的函数值和参数都是evaluated as usual并保存,但是不会调用实际函数。

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

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

defer f("a")

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

下一步:

defer f(g("a"))

在这种情况下,将评估函数值(将为f)并评估参数,这意味着g将被"a"调用(因为{{1} }的返回值是g的参数。

下一步:

f

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

f

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

回到您的示例:

f

计算函数值,它是defer def("defered line")() 的返回值,因此调用defdef的返回值将被推迟。其参数已评估,但实际上没有参数。

所以逻辑上,这是发生的情况:

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

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

  • defered line"的参数进行评估:这是一个常量def
  • "defered line"被调用,它显示def及其参数:tier up
  • 调用defered line的返回值,这是递延的。
  • 函数def打印:main
  • 函数main返回,因此现在调用延迟函数。延迟功能将打印main

答案 1 :(得分:0)

  

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

上面的句子表示延迟的函数参数在延迟的行处进行评估,但是该函数将在周围的函数main返回之后运行。

  

defer语句将函数调用推送到列表上。的清单   周围的函数返回后,将执行保存的调用。延期   通常用于简化执行各种清理的功能   动作。

在周围的函数返回后,将按照后进先出的顺序执行延迟的函数调用。

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

上面的行清楚地表明它将把值返回给主函数。

例如:-

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

上面的函数将返回2而不是1的值。这就是为什么这行

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

将在最后一次调用。

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

答案 2 :(得分:0)

defer def("defered line")()

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

def("defered line")评估为func(){ fmt.Println("clean up") },但有副作用。

答案 3 :(得分:0)

如果将传递给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 它何时会运行。