一尘不染

在Go中使用defer

go

deferGo 的用途是什么?语言文档说它在周围的函数返回时执行。为什么不将代码放在给定函数的末尾?


阅读 238

收藏
2020-07-02

共1个答案

一尘不染

我们通常defer用来关闭或释放资源。

周围的函数会在返回之前执行所有延迟的函数调用,即使它会慌乱。如果仅将函数调用放在周围函数的末尾,则在发生紧急情况时将跳过该调用。

而且,延迟函数调用可以通过调用recover内置函数来处理紧急情况。这不能通过函数结尾处的普通函数调用来完成。

每个延迟的调用都放在堆栈中,并在周围函数结束时以相反的顺序执行。颠倒顺序有助于正确分配资源。

defer必须调用该语句才能调用函数。

您可以将其视为实现try-catch-finally块的另一种方法。

结束像try-finally

func main() {
    f, err := os.Create("file")
    if err != nil {
        panic("cannot create file")
    }
    defer f.Close()
    // no matter what happens here file will be closed
    // for sake of simplicity I skip checking close result
    fmt.Fprintf(f,"hello")
}

结束和恐慌处理,例如 try-catch-finally

func main() {
    defer func() {
        msg := recover()
        fmt.Println(msg)
    }()
    f, err := os.Create(".") // . is a current directory
    if err != nil {
        panic("cannot create file")
    }
    defer f.Close()
    // no matter what happens here file will be closed
    // for sake of simplicity I skip checking close result
    fmt.Fprintf(f,"hello")
}

与try-catch-finally相比,好处是没有块和变量作用域的嵌套。这简化了周围功能的结构。

就像finally块一样,如果延迟函数调用可以到达返回的数据,则它们也可以修改返回值。

func yes() (text string) {
    defer func() {
       text = "no"
    }()
    return "yes"
}

func main() {
    fmt.Println(yes())
}
2020-07-02