代码之家  ›  专栏  ›  技术社区  ›  RudziankoÅ­

延迟调用的参数将立即计算

  •  3
  • RudziankoÅ­  · 技术社区  · 7 年前

    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 回复  |  直到 7 年前
        1
  •  5
  •   icza    7 年前

    要了解延迟和评估是如何工作的,首先让我们看看 Spec: defer statements:

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

    同时计算函数值(其调用被延迟)及其参数。但是延迟函数还没有被调用。

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

    defer f("a")
    

    在这种情况下,对函数值进行评估(将 f ,然后对参数进行评估,这是一个常数,所以 "a" .

    下一步:

    defer f(g("a"))
    

    在这种情况下,对函数值进行评估(将 f )并对参数进行评估,这意味着 g 将与呼叫 “A” (因为 G 的返回值是参数to f )

    下一步:

    defer f()()
    

    如果 f 函数返回一个函数。将对函数值进行评估(这意味着 f 将被调用!)但它的返回值不会被调用,这就是将要延迟的。

    defer f(g())()
    

    在这种情况下,延迟函数是 f ,所以要评估延迟函数值, f 一定要打电话来,要做到这一点 G 必须先调用。的返回值 f 将延迟(未调用)。

    回到你的例子:

    defer def("defered line")()
    

    对函数值进行计算,该值是 def 如此 DEF 被调用。的返回值 DEF 将被推迟。它的参数是经过评估的,但实际上它没有参数。

    所以 逻辑上 这就是发生的事情:

    1. 计算延迟函数值,这要求:
      • DEF 必须调用函数,这要求:
        • 参数到 DEF 被计算,它是一个常量:“ defered line"
    2. 对延迟函数的参数进行计算;由于没有参数,因此完成此步骤。

    这就是发生的事 按顺序 如果我们设计出上述结构:

    • 参数到 DEF 被评估:它是一个常量 "defered line"
    • DEF 叫什么印刷品 tier up 它的论点是: defered line
    • 的返回值 DEF 打电话来了,这是推迟的。
    • 功能 main 印刷品: 主要的
    • 功能 主要的 返回,因此现在调用延迟函数。延迟函数打印 clean up
        2
  •  0
  •   Himanshu    7 年前

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

    上面的句子意味着延迟函数参数是在延迟的行上计算的,但是函数将在周围的函数之后运行 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

        3
  •  0
  •   kostix    7 年前

    更清楚的是,如果你改变你要传递给的论点 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 通过第一条命令行 用户在运行程序时提供的参数, 拿什么都行 酒吧 返回并附加 它的字符串文本。

    然后保存生成的字符串,并将其传递给 DEF 它什么时候运行。

        4
  •  0
  •   Uvelichitel    7 年前

    defer def("defered line")()
    

    def("defered line") () 被延迟调用的参数被立即计算。

    def(“延期行”) 计算结果为 func(){ fmt.Println("clean up") } 有副作用。