Go语言 当资源超出了周围函数的作用域时,如何延迟资源清理?

axzmvihb  于 2023-10-14  发布在  Go
关注(0)|答案(2)|浏览(124)

让我们以this piece of code为例,它使日志记录器写入本地文件而不是标准输出:

  1. f, err := os.OpenFile("filename", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
  2. if err != nil {
  3. log.Fatal(err)
  4. }
  5. defer f.Close()
  6. log.SetOutput(f)

作者将这段代码直接放入main()函数中,使其按预期工作。但是,如果我想把这段代码放到一个main()可以调用的专用函数中,那么它将不再工作,因为f.Close()将在日志记录器使用之前被调用。
例如(如果上面的代码现在在一个名为logToFile()的函数中):

  1. main() {
  2. logToFile()
  3. log.Print("I'm going to end up in stdout\n")
  4. }
  • this是否可以移动到它自己的函数中,并仍然按预期工作?

我在打开/关闭数据库连接时也遇到过同样的情况。看起来唯一的方法是在main()内部完成这两件事,但我认为如果我们可以将代码划分为函数,代码看起来会更清晰,更像SoC。这是围棋中的禁忌吗

dsf9zpds

dsf9zpds1#

你在找这样的东西吗?

  1. type closerFunc func() error
  2. func logToFile(path string) closerFunc {
  3. f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
  4. if err != nil {
  5. log.Fatal(err)
  6. }
  7. log.SetOutput(f)
  8. return func() error {
  9. return f.Close()
  10. }
  11. }

用途:

  1. func main() {
  2. closerFn := logToFile("filename")
  3. defer closerFn()
  4. log.Print("logs to file\n")
  5. }
展开查看全部
t8e9dugd

t8e9dugd2#

一种选择是使用continuation-passing style,将在defer块中执行的代码作为显式参数传递:

  1. func withLogToFile(filename string, body func()) {
  2. f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
  3. if err != nil {
  4. log.Fatal(err)
  5. }
  6. prevOut := log.Writer()
  7. log.SetOutput(f)
  8. defer func() {
  9. log.SetOutput(prevOut)
  10. if err := f.Close(); err != nil {
  11. log.Fatal(err)
  12. }
  13. }()
  14. body()
  15. }

然后调用站点变为:

  1. func main() {
  2. withLogToFile(filename, func() {
  3. log.Print("I'm going to end up in ", filename)
  4. })
  5. }

https://play.golang.org/p/ebCvtzufU5U

展开查看全部

相关问题