Go语言 延迟调用的参数立即计算

ogsagwnx  于 2023-09-28  发布在  Go
关注(0)|答案(4)|浏览(89)

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
这里什么是延迟的,什么是立即评估的?

nqwrtyyt

nqwrtyyt1#

要了解延迟和评估是如何工作的,首先让我们看看Spec:defer语句:
每次执行“defer”语句时,函数值和调用的参数都会照常计算并重新保存,但实际的函数不会被调用。
函数值(其调用被延迟)及其参数都被计算。但是延迟函数还没有被调用。
让我们通过一些小步骤来迭代您的示例:

defer f("a")

在这种情况下,函数值被求值(将是f),参数被求值,这是一个常数,所以它将是"a"
下一步:

defer f(g("a"))

在这种情况下,函数值被求值(将是f),参数也被求值,这意味着g将用"a"调用(因为g的返回值是f的参数)。
下一步:

defer f()()

如果f函数返回一个函数,则此选项有效。函数值将被计算(这意味着将调用f!),但它的返回值不会被调用,这就是将被延迟的内容。

defer f(g())()

在本例中,延迟函数是f的返回值,因此要计算延迟函数的值,必须调用f,而要做到这一点,必须先调用gf的返回值将被延迟(不调用)。

返回您的示例:

defer def("defered line")()

函数值被求值,它是def的返回值,因此调用defdef的返回值将被延迟。它的参数被求值,但实际上它没有参数。
所以逻辑上是这样的:

  • 计算延迟函数值,这要求:
  • 必须调用def函数,要求:
  • def的参数被计算,它是一个常量:“defered line"
  • 计算延迟函数的参数;因为没有参数,所以完成该步骤。

这就是如果我们布局上面的结构,顺序地发生的事情:

  • def的参数进行评估:它是一个常数"defered line"
  • 调用def,输出tier up及其参数:defered line
  • def的返回值被not调用,这就是延迟的原因。
  • 功能main打印:main
  • 函数main返回,因此现在调用延迟函数。deferred函数打印clean up
hzbexzde

hzbexzde2#

延迟调用的参数会立即计算,但直到周围的函数返回后才执行函数调用。
上面的句子意味着延迟的函数参数在它们被延迟的那一行被求值,但是函数将在周围的函数main返回之后运行。
defer语句将函数调用推送到列表上。已保存调用的列表在周围函数返回后执行。Defer通常用于简化执行各种清理操作的函数。
延迟的函数调用在周围函数返回后按后进先出顺序执行。
延迟函数可以读取返回函数的命名返回值并将其赋给返回函数。
上面的一行清楚地说明了它将返回值到main函数。
例如:-

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

上面的函数将返回2值而不是1。所以这条线

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

将在最后被召唤。
有关defer的更多信息。Please read golang blog for defer

qnakjoqk

qnakjoqk3#

如果将传递给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

1zmg4dgp

1zmg4dgp4#

defer def("defered line")()

def("defered line")()是立即计算的延迟调用的参数。
def("defered line")计算为func(){ fmt.Println("clean up") },但有副作用。

相关问题