英文:
How to capture errors when importing a module in Golang?
问题
在Go语言中,当我导入一个模块时,它的init()函数会被执行(我猜在main()函数之前?),在这个函数中可能会产生一些错误。我该如何捕获这些错误并在我的代码中进行处理?
英文:
In golang, when I import a module, its init() gets executed (before main() I assume?), it is possible some error is generated in this function. How can I capture these errors and handle them in my own code?
答案1
得分: 6
Go语言中的错误是作为返回值返回的,你可能已经知道了。由于init()函数不返回任何内容,唯一的选择是在init中使用panic()来处理错误。
一个在init中使用panic的包可能设计得不太好,尽管可能存在一些合理的使用情况。
在这种情况下,recover()不是一个选择,因为init在main之前运行。所以如果你不能编辑相关的包,那么就没有办法了。
这就是为什么应该谨慎使用panic和recover的原因,只在真正需要"恐慌"的情况下使用。
@twotwotwo在"effective Go"中提供了以下描述(针对init的情况):
如果库真的无法完成设置,使用panic可能是合理的,可以这么说
所以:如果你的init函数需要报告错误,请问自己这段代码是否真的应该放在init中,或者是否更适合放在其他地方。如果确实必须使用init,考虑在包内部设置一个错误标志,并说明任何客户端都必须检查该错误。
英文:
Errors in Go are return values, as you may know. As init() does not return anything, the only alternative is to panic() in init if anything goes wrong.
A package that panics on init is arguably not very well designed, although there may be valid use cases for this.
Given the circumstances, recover() is not an option, because init is run before main. So if you can't edit the package in question, then you're out of luck.
This is one of the reasons why panic and recover should be used sparingly, only in situations where literally "panicking" makes sense.
@twotwotwo contributed the following quote from "effective Go" that describes this (for the init case):
> if the library truly cannot set itself up, it might be reasonable to panic, so to speak
So: if your init function needs to report an error, then ask yourself if that code really belongs in init or would be better kept somewhere else. If it really has to be init, consider setting an error flag inside of the package and document that any client must check that error.
答案2
得分: 5
是的,包的init()
函数在main()
函数之前运行,详见语言规范中的Package initialization。
但是,你不能处理在包的init()
函数中发生的错误。即使你可以,这意味着你的程序依赖的某个包未能成功初始化,你也无法预料到它的行为。
包的init()
函数没有返回值,也不能以有意义的方式引发恢复性的panic。如果init()
函数发生panic,程序将终止运行。
由于init()
函数不是由你调用的(例如从main()
函数中),你无法从那里进行恢复。处理包在初始化过程中的错误是包本身的责任,而不是包的使用者的责任。
在init()
函数中发生错误的一种选项是将错误状态存储在一个变量中(例如,一个可导出的变量,或者一个非导出的变量,但可以通过一个导出的函数进行查询)。但这只有在继续执行是合理的情况下才应该使用,并且这也是包本身的任务和责任(存储/报告错误),而不是包的使用者的责任。你无法在没有包的配合下做到这一点(无法“捕获”未处理/未报告的错误和panic)。
英文:
Yes, package init()
functions run before the main()
function, see Package initialization in the language specification.
And no, you can't handle errors occurred in package init()
functions. Even if you could, that would mean a package your program depends on failed to initialize and you wouldn't know what to expect from it.
Package init()
functions have no return values and they can't panic in a meaningful way that was meant to recover from. If an init()
function panics, the program terminates.
Since init()
functions are not called by you (e.g. from the main()
function), you can't recover from there. It is the responsibility of the package itself to handle errors during its initialization, not the users of the package.
One option to signal error happening during an init()
is to store the error state in a variable (e.g. exported, or unexported but queryable by an exported function). But this should be used only if it is reasonable to continue, and this is also the task/responsibility of the package itself (to store/report the error) and not the users of the package. You can't do this without the cooperation of the package (you can't "catch" unhandled/unreported errors and panics).
答案3
得分: 1
不直接,但你可以使用类似这样的方式:
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)
}
// ...
}
英文:
Not directly, but you could using something like this:
package mypkg
var InitErr error
var Foo MyFoo
func init() {
Foo, InitErr = makeInitialisation()
// ...
}
And then in your main:
package main
import "foo/bar/mypkg"
func main() {
if (mypkg.InitErr != nil) {
panic(err)
}
// ...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论