在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条答案
按热度按时间nqwrtyyt1#
要了解延迟和评估是如何工作的,首先让我们看看Spec:defer语句:
每次执行“defer”语句时,函数值和调用的参数都会照常计算并重新保存,但实际的函数不会被调用。
函数值(其调用被延迟)及其参数都被计算。但是延迟函数还没有被调用。
让我们通过一些小步骤来迭代您的示例:
在这种情况下,函数值被求值(将是
f
),参数被求值,这是一个常数,所以它将是"a"
。下一步:
在这种情况下,函数值被求值(将是
f
),参数也被求值,这意味着g
将用"a"
调用(因为g
的返回值是f
的参数)。下一步:
如果
f
函数返回一个函数,则此选项有效。函数值将被计算(这意味着将调用f
!),但它的返回值不会被调用,这就是将被延迟的内容。在本例中,延迟函数是
f
的返回值,因此要计算延迟函数的值,必须调用f
,而要做到这一点,必须先调用g
。f
的返回值将被延迟(不调用)。返回您的示例:
函数值被求值,它是
def
的返回值,因此调用def
。def
的返回值将被延迟。它的参数被求值,但实际上它没有参数。所以逻辑上是这样的:
def
函数,要求:def
的参数被计算,它是一个常量:“defered line"
这就是如果我们布局上面的结构,顺序地发生的事情:
def
的参数进行评估:它是一个常数"defered line"
def
,输出tier up
及其参数:defered line
def
的返回值被not调用,这就是延迟的原因。main
打印:main
main
返回,因此现在调用延迟函数。deferred函数打印clean up
hzbexzde2#
延迟调用的参数会立即计算,但直到周围的函数返回后才执行函数调用。
上面的句子意味着延迟的函数参数在它们被延迟的那一行被求值,但是函数将在周围的函数
main
返回之后运行。defer语句将函数调用推送到列表上。已保存调用的列表在周围函数返回后执行。Defer通常用于简化执行各种清理操作的函数。
延迟的函数调用在周围函数返回后按后进先出顺序执行。
延迟函数可以读取返回函数的命名返回值并将其赋给返回函数。
上面的一行清楚地说明了它将返回值到main函数。
例如:-
上面的函数将返回
2
值而不是1
。所以这条线将在最后被召唤。
有关defer的更多信息。Please read golang blog for defer
qnakjoqk3#
如果将传递给
def(string)
的参数从字符串字面量(在编译时计算)更改为更有趣的内容,会更清楚,比如:当执行
defer def(bar(os.Args[1]) + "defered line")()
语句时,def
的参数将被完全求值,这意味着调用bar
,将用户在运行程序时提供的第一个命令行参数传递给它,接受bar
返回的任何参数并向其追加一个字符串。然后保存生成的字符串,并在运行时将其传递给
def
。1zmg4dgp4#
在
def("defered line")
和()
是立即计算的延迟调用的参数。def("defered line")
计算为func(){ fmt.Println("clean up") }
,但有副作用。