有没有像 init() 相反的 finally() 函数在 Go 语言中可以使用?

13

在Go语言中,有没有与包内的init()相反的功能?

1个回答

10
这个问题之前已经被Go团队讨论过了,并且结论是不支持它。引用minux:
个人而言,我更喜欢程序退出的方式与程序崩溃的处理方式完全相同的风格。我相信无论你多么努力,你的程序在某些意外情况下仍然可能崩溃;例如,内存短缺可能会导致任何良好行为的Go程序崩溃,而你对此无能为力;因此,最好为它们进行设计。如果你遵循这个原则,就不会感到需要使用atexit来清理(因为当你的程序崩溃时,atexit将无法工作,所以你根本不能依赖它)。
但你仍有一些选择:
处理CTRL+C 如果你想在程序被CTRL+CSIGINT)终止时执行某些操作,你可以这样做,请参见:

Golang: 是否可以以“defer”方式捕获Ctrl+C信号并运行清理函数?

对象终结器

还要注意,您可以为指针值注册终结器函数。当垃圾收集器发现具有关联终结器的不可达块时,它会清除关联并在单独的goroutine中运行f(x)

您可以使用runtime.SetFinalizer()注册此类终结器,这可能已经足够了,但请注意:

不能保证终结器在程序退出之前运行,因此通常仅在长时间运行的程序期间释放与对象关联的非内存资源时才有用。

请参阅此示例:

type Person struct {
    Name string
    Age  int
}

func main() {
    go func() {
        p := &Person{"Bob", 20}
        runtime.SetFinalizer(p, func(p2 *Person) {
            log.Println("Finalizing", p2)
        })
        runtime.GC()
    }()

    time.Sleep(time.Second * 1)
    log.Println("Done")
}

输出(前往Playground):
2009/11/10 23:00:00 Finalizing &{Bob 20}
2009/11/10 23:00:01 Done

1
我认为,滥用finalize函数来做“用户空间”清理是代码质量不佳的标志。相反,一个人应该设计整个应用程序以控制关机为中心,并在满足某些条件时执行该受控关机(比如接收到SIGINT或SIGTERM)。这是一个很好的起点:http://blog.labix.org/2011/10/09/death-of-goroutines-under-control。 - kostix
参见 - kostix
2
我还要补充一点,创建一个需要“atexit”钩子的包是一个非常糟糕的设计。该包应该只导出“某些东西”,用户必须显式地初始化和显式地去初始化,然后让用户在真正需要时执行这些操作。 - kostix
1
@kostix 我同意,依赖这样的函数是不好的设计,这就是为什么没有一流的支持。只是展示可用选项。 - icza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接