在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
这里延迟什么,立即评估什么?
答案 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
,并且必须先调用f
。 g
的返回值将被延迟(不调用)。
回到您的示例:
f
计算函数值,它是defer def("defered line")()
的返回值,因此调用def
。 def
的返回值将被推迟。其参数已评估,但实际上没有参数。
所以逻辑上,这是发生的情况:
def
函数必须被调用,这要求:
def
的参数进行评估,它是一个常量:“ def
如果我们布置以上结构,则会依次发生:
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
它何时会运行。