在golang中使用延迟

Shu*_*ary 37 go

defergolang有什么用?语言文档说它是在周围函数返回时执行的.为什么不把代码放在给定函数的末尾?

Grz*_*Żur 47

我们defer通常使用关闭或取消分配资源.保证在每种情况下运行.如有任何退货或恐慌.当您将功能放在最后时,您没有这种保证.

此外,一个deffered函数调用可以通过调用recover内置函数来处理恐慌.这不能通过最后的功能来完成.

您可以将其视为defer块的另一种实现.

结束一样 try-catch-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")
}
Run Code Online (Sandbox Code Playgroud)

关闭和恐慌处理都一样 try-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")
}
Run Code Online (Sandbox Code Playgroud)

try-catch-finally的好处是没有嵌套的块和可变范围简化了函数的结构.

类似于finally块,延迟函数调用也可以修改返回值,如果它们可以到达返回的数据.

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

func main() {
    fmt.Println(yes())
}
Run Code Online (Sandbox Code Playgroud)

  • FWIW,“保证”在这里使用起来有点强烈。显然,在某些情况下,您的延迟函数将无法运行:例如,也许有人对您的 CPU 使用了霰弹枪。更一般地,也许周围的函数根本不会返回。我更愿意说,在周围的函数返回之前,它将执行所有延迟的函数。 (2认同)

May*_*yur 11

这里已经有很好的答案了。我想再提一个用例。

func BillCustomer(c *Customer) error {
    c.mutex.Lock()
    defer c.mutex.Unlock()

    if err := c.Bill(); err != nil {
        return err
    }

    if err := c.Notify(); err != nil {
        return err
    }

    // ... do more stuff ...

    return nil
}
Run Code Online (Sandbox Code Playgroud)

defer在这个例子中可以确保无论怎样BillCustomer的回报时,mutexunlocked之前立即BillCustomer返回。这是非常有用的,因为没有defer你就必须要记住unlockmutex每一个地方,该功能可能可能return

参考


Rav*_*avi 6

好吧,并不总是保证您的代码可能会到达函数的末尾(例如,错误或某些其他条件可能会迫使您在函数结束之前很早地返回)。defer 语句确保分配给它的任何函数都得到执行,即使函数发生混乱或代码在函数结束之前返回。

defer 语句还有助于保持代码干净,尤其是。在一个函数中有多个 return 语句的情况下。当一个人需要在返回之前释放资源时(例如,假设您在函数开始时有一个访问资源的开放调用 - 为此必须在函数返回之前调用相应的关闭以避免资源泄漏。并说您的函数有多个 return 语句,可能针对包括错误检查在内的不同条件。在这种情况下,如果没有延迟,您通常会在每个 return 语句之前调用该资源的 close)。defer 语句确保你传递给它的函数总是被调用,而不管函数在哪里返回,从而使你免于额外的内务工作。

也可以在同一个函数中多次调用 defer。例如:如果您通过函数分配了不同的资源,这些资源需要在返回之前最终释放,那么您可以在分配后为每个资源调用 defer,这些函数将按照与调用它们的顺序相反的顺序执行当函数退出时。