当该资源超出周围功能的范围时,如何推迟资源清理?
How to defer resource cleanup when that resource outlives the scope of the surrounding function?
让我们以 this piece of code 为例,它使记录器写入本地文件而不是标准输出:
f, err := os.OpenFile("filename", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
log.SetOutput(f)
作者将此代码直接放入 main()
函数中,使其按预期工作。但是,如果我想将此代码放入一个专用函数中,然后 main()
可能会调用它,那么它将不再起作用,因为 f.Close()
将在记录器被使用之前被调用。
例如(如果上面的代码现在在一个名为 logToFile()
的函数中):
main() {
logToFile()
log.Print("I'm going to end up in stdout\n")
}
可以将它移到它自己的函数中,并且仍然按预期工作吗?
我在 opening/closing 的数据库连接中遇到过相同的情况。似乎唯一的方法是在 main()
中完成这两件事,但我认为如果我们可以将代码划分为函数,代码看起来会更清晰,也更像 SoC。这是 Go 中的禁忌吗?
您正在寻找这样的东西吗?
type closerFunc func() error
func logToFile(path string) closerFunc {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
return func() error {
return f.Close()
}
}
使用:
func main() {
closerFn := logToFile("filename")
defer closerFn()
log.Print("logs to file\n")
}
一种选择是使用 continuation-passing style,将要在 defer
块中执行的代码作为显式参数传递:
func withLogToFile(filename string, body func()) {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
prevOut := log.Writer()
log.SetOutput(f)
defer func() {
log.SetOutput(prevOut)
if err := f.Close(); err != nil {
log.Fatal(err)
}
}()
body()
}
那么调用站点变为:
func main() {
withLogToFile(filename, func() {
log.Print("I'm going to end up in ", filename)
})
}
让我们以 this piece of code 为例,它使记录器写入本地文件而不是标准输出:
f, err := os.OpenFile("filename", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
log.SetOutput(f)
作者将此代码直接放入 main()
函数中,使其按预期工作。但是,如果我想将此代码放入一个专用函数中,然后 main()
可能会调用它,那么它将不再起作用,因为 f.Close()
将在记录器被使用之前被调用。
例如(如果上面的代码现在在一个名为 logToFile()
的函数中):
main() {
logToFile()
log.Print("I'm going to end up in stdout\n")
}
可以将它移到它自己的函数中,并且仍然按预期工作吗?
我在 opening/closing 的数据库连接中遇到过相同的情况。似乎唯一的方法是在 main()
中完成这两件事,但我认为如果我们可以将代码划分为函数,代码看起来会更清晰,也更像 SoC。这是 Go 中的禁忌吗?
您正在寻找这样的东西吗?
type closerFunc func() error
func logToFile(path string) closerFunc {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
return func() error {
return f.Close()
}
}
使用:
func main() {
closerFn := logToFile("filename")
defer closerFn()
log.Print("logs to file\n")
}
一种选择是使用 continuation-passing style,将要在 defer
块中执行的代码作为显式参数传递:
func withLogToFile(filename string, body func()) {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
prevOut := log.Writer()
log.SetOutput(f)
defer func() {
log.SetOutput(prevOut)
if err := f.Close(); err != nil {
log.Fatal(err)
}
}()
body()
}
那么调用站点变为:
func main() {
withLogToFile(filename, func() {
log.Print("I'm going to end up in ", filename)
})
}