延迟语句如何正常工作

时间:2014-07-16 08:00:42

标签: go

我尝试学习golang并使用有效的go作为讲座。我坚持资本延期,看下面的代码

package main

import "fmt"

func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func a() {
    defer un(trace("a"))
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}

func main() {
    b()
}

作为输出我已经

entering: b
in b
entering: a
in a
leaving: a
leaving: b

我知道,defer语句将在函数中的return语句之后执行。但在这里,为什么输入:b是第一个输出?我预计在b中作为第一个输出!

2 个答案:

答案 0 :(得分:8)

根据http://golang.org/doc/effective_go.html#defer

  

延迟函数的参数(如果函数是方法,包括接收器)在延迟执行时计算,而不是在调用执行时计算。除了避免担心变量在函数执行时更改值,这意味着单个延迟调用站点可以推迟多个函数执行。

所以推迟函数的参数(在你的情况下跟踪(" b"))首先评估

答案 1 :(得分:2)

简化,

package main

import "fmt"

func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
}

func main() {
    b()
}

输出:

entering: b
in b
leaving: b

因为"在defer执行"时评估延迟函数的参数,

defer un(trace("b"))
函数b中的

语句是使用显式范围,等同于

{
    unarg := trace("b")
    defer un(unarg)
}

因此,等效地,

package main

import "fmt"

func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func b() {
    {
        unarg := trace("b")
        defer un(unarg)
    }
    fmt.Println("in b")
}

func main() {
    b()
}

输出:

entering: b
in b
leaving: b

等效地,完整的例子,

package main

import "fmt"

func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func a() {
    {
        unarg := trace("a")
        defer un(unarg)
    }
    fmt.Println("in a")
}

func b() {
    {
        unarg := trace("b")
        defer un(unarg)
    }
    fmt.Println("in b")
    a()
}

func main() {
    b()
}

输出:

entering: b
in b
entering: a
in a
leaving: a
leaving: b