如何理解推迟陈述

时间:2017-10-02 08:01:39

标签: go

我在golang中有两个关于延迟语句的例子,第一个是不正确的,第二个是正确的。但我认为他们有同样的问题,在我看来,我认为第二个仍然存在文件描述符耗尽的风险,任何人都可以帮助我澄清为什么第二个是正确的?谢谢!

例1:

for _, filename := range filenames {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close() // NOTE: risky; could run out of file descriptors
    // ...process f...
 }

例2:

for _, filename := range filenames {
    if err := doFile(filename); err != nil {
        return err
    }
}
func doFile(filename string) error {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    // ...process f...
}

1 个答案:

答案 0 :(得分:3)

当封闭函数返回时,延迟函数运行。 Spec: Defer statements:

  

“defer”语句调用一个函数,该函数的执行被推迟到周围函数返回的那一刻,因为周围的函数执行return statement,到达function body的末尾,或者因为相应的goroutine是panicking

在您的第一个示例中,您使用了一个for循环,其中您使用defer语句,但延迟函数将不会在迭代结束时执行,仅在{{1}之后} loop(当封闭函数结束时)。这意味着您在for循环内打开的所有文件将保持打开状态,直到“结束”。如果for包含一千个有效的文件名,则循环将(尝试)在开始关闭任何文件之前打开一千个文件。

在您的第二个示例中,您将处理文件的“外包”发送到单独的功能。在此函数中使用filenames根本不同,因为当此函数返回时,将首先调用延迟函数(defer)。因此,在您的第二个示例中,无论File.Close()包含多少元素,最多只有1个文件由发布的代码打开。