gpt4 book ai didi

loops - 在循环中使用 defer 释放资源的正确方法?

转载 作者:IT老高 更新时间:2023-10-28 13:04:55 24 4
gpt4 key购买 nike

我需要在循环中对数据库进行 SQL 查询:

for rows.Next() {

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

// do something with `fields`

}

什么会更好:保持原样或在循环后移动 defer:

for rows.Next() {

fields, err := db.Query(.....)
if err != nil {
// ...
}

// do something with `fields`
}

defer fields.Close()

还是别的什么?

最佳答案

延迟函数的执行不仅延迟,延迟到周围函数返回的那一刻,即使封闭函数突然终止,它也会执行,例如 panic 。 Spec: Defer statements:

A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.

每当您创建一个值或资源以提供正确关闭/处置它的方法时,您应该始终使用 defer 语句来确保它被释放,即使您的其他代码 panic 到防止泄漏内存或其他系统资源。

确实,如果你在循环中分配资源,你不应该简单地使用defer,因为那样释放资源不会尽早和< em>应该(在每次迭代结束时),仅在 for 语句之后(仅在所有迭代之后)。

你应该做的是,如果你有一个分配这些资源的片段,将它包装在一个函数中——匿名函数或命名函数——并且在该函数中你可以使用 defer,并且资源将在不再需要时立即释放,重要的是即使您的代码中存在可能导致 panic 的错误。

例子:

for rows.Next() {
func() {
fields, err := db.Query(...)
if err != nil {
// Handle error and return
return
}
defer fields.Close()

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

或者如果放入一个命名函数:

func foo(rs *db.Rows) {
fields, err := db.Query(...)
if err != nil {
// Handle error and return
return
}
defer fields.Close()

// do something with `fields`
}

并称它为:

for rows.Next() {
foo(rs)
}

此外,如果您想在第一个错误时终止,您可以从 foo() 返回错误:

func foo(rs *db.Rows) 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
}
}

另请注意 Rows.Close()返回一个错误,当使用 defer 调用该错误时会被丢弃。如果我们想检查返回的错误,我们可以使用这样的匿名函数:

func foo(rs *db.Rows) (err error) {
fields, err := db.Query(...)
if err != nil {
return fmt.Errorf("db.Query error: %w", err)
}
defer func() {
if err = fields.Close(); err != nil {
err = fmt.Errorf("Rows.Close() error: %w", err)
}
}()

// do something with `fields`
return nil
}

关于loops - 在循环中使用 defer 释放资源的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45617758/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com