在 Golang 中导入模块时如何捕获错误?

How to capture errors when importing a module in Golang?

在 golang 中,当我导入一个模块时,它的 init() 被执行(我假设在 main() 之前?),这个函数中可能会产生一些错误。我如何捕获这些错误并在我自己的代码中处理它们?

Go 中的错误是 return 个值,您可能知道。由于 init() 没有 return 任何东西,如果出现任何问题,唯一的选择是在 init 中使用 panic()。

在 init 时出现恐慌的包可以说设计得不是很好,尽管可能有有效的用例。

在这种情况下,recover() 不是一个选项,因为 init 在 main 之前 运行。所以如果你不能编辑有问题的包,那你就倒霉了。

这就是为什么应谨慎使用 panic 和 recover 的原因之一,仅在字面上 "panicking" 有意义的情况下使用。

@twotwotwo 从 "effective Go" 引用了以下引述(对于初始情况):

if the library truly cannot set itself up, it might be reasonable to panic, so to speak

因此:如果您的 init 函数需要报告错误,那么问问自己该代码是否真的属于 init 或最好保存在其他地方。如果它确实必须是 init,请考虑在包内设置一个错误标志,并记录任何客户端必须检查该错误。

是的,在 main() 函数之前封装 init() 函数 运行,请参阅语言规范中的 Package initialization

不,您不能处理包 init() 函数中发生的错误。即使你可以,那也意味着你的程序依赖的包无法初始化,你不知道它会带来什么。

init() 函数没有 return 值,它们不会以有意义的方式发生恐慌,这意味着可以从中恢复。如果 init() 函数崩溃,程序将终止。

由于您未调用 init() 函数(例如从 main() 函数调用),因此您无法从那里恢复。在初始化过程中处理错误是包本身的责任,而不是包的用户。

init() 期间发出错误信号的一个选项是将错误状态存储在变量中(例如已导出,或未导出但可由导出函数查询)。但这只有在合理继续时才应该使用,这也是包本身的task/responsibility(到store/report错误)而不是包的用户。没有包的配合你做不到这一点(你不能"catch"unhandled/unreported错误和恐慌)。

不是直接的,但你可以使用这样的东西:

package mypkg

var InitErr error
var Foo MyFoo

func init() {
    Foo, InitErr = makeInitialisation()
    // ...
}

然后在你的主要部分:

package main

import "foo/bar/mypkg"

func main() {
    if (mypkg.InitErr != nil) {
        panic(err)
    }
    // ...
}