尽可能地避免在 for 循环中使用 defer,因为这可能会导致资源泄漏(Possible resource leak, 'defer' is called in the 'for' loop)。

defer 不是基于代码块的,而是基于函数的。你在循环中分配资源,那么不应该简单地使用 defer,因为释放资源不会尽可能早地发生(在每次迭代结束时),只有在 for 语句之后(所有迭代之后),即所在函数结束时,defer 函数才会被执行。这带来的后果就是,如果迭代次数过多,那么可能导致资源长时间得不到释放,造成泄漏。

// Bad
for rows.Next() {
   fields, err := db.Query(.....)
   if err != nil {
      // ...
   }
   defer fields.Close()

   // do something with `fields`

}

如果有一个类似上面分配资源的代码段,我们应该将其包裹在一个函数中(匿名函数或有名函数)。在该函数中,使用 defer,资源将在不需要时被立即释放。

// 1.将 defer 放在匿名函数中
for rows.Next() {
    func() {
        fields, err := db.Query(...)
        if err != nil {
            // Handle error and return
            return
        }
        defer fields.Close()

        // do something with `fields`
    }()
}

// 2.将 defer 放在有名函数中然后调用之
func foo(r *db.Row) error {
    fields, err := db.Query(...)
    if err != nil {
        return fmt.Errorf("db.Query error: %w", err)
    }
    defer fields.Close()

    // do something with `fields`
    return nil
}

// 调用有名函数
for rows.Next() {
    if err := foo(rs); err != nil {
        // Handle error and return
        return
    }
}
powered by Gitbook该文章修订时间: 2024-03-22 15:30:00

results matching ""

    No results matching ""