英文:
is it wrong to treat panic / recover as throw / catch
问题
作为一个新的Go爱好者,试图使用Go的错误处理方式。明确一点 - 我喜欢异常。
我有一个接受连接、处理一系列请求并回复的服务器。我发现我可以在深层处理代码中使用以下代码:
if err != nil {
panic(err)
}
并在客户端连接代码中使用以下代码(每个连接在一个goroutine中):
defer func() {
if err := recover(); err != nil {
log.Printf("%s: %s", err, debug.Stack()) // line 20
}
}()
这样可以很好地封装一切,强制关闭连接(其他defer语句也会执行),而我的服务器会继续正常运行。
但是这感觉非常像一个throw/catch的场景 - 而Go语言声称不支持这种方式。问题是:
- 这种方式稳定吗?也就是说,作为一种持续的生活方式,恢复panic是可以接受的。它不仅仅是稍微延迟立即关闭的意图。
- 我在这个主题上寻找了讨论,但没有找到任何相关的信息 - 有什么指引吗?
我觉得答案是“是的,它可以工作”,并且可以在你自己的代码中使用,但是不应该在面向更广泛使用的库中使用panic。一个库的标准和礼貌的行为方式是通过错误返回来处理。
英文:
Speaking as a new go enthusiast trying to work with the go way of error handling. To be clear - I like exceptions.
I have a server that accepts a connection , processes a set of requests and replies to them. I found that I can do
if err != nil{
panic(err)
}
in the deep down processing code
and have
defer func() {
if err := recover(); err != nil {
log.Printf("%s: %s", err, debug.Stack()) // line 20
}
}()
in the client connection code (each connection is in a goroutine). This nicely wraps everything up, forcefully closes the connection (other defers fire) and my server continues to hum along.
But this feels an awful lot like a throw/catch scenario - which golang states it doesn't support. Questions
- is this stable. ie recovering a panic is an OK thing to do as an
ongoing way of life. Its not intended to just slightly defer an
immediate shutdown - I looked for a discussion on this topic and did not find it anywhere - any pointers?
I feel that the answer is 'yes it works' and can be used inside you own code, but panic should NOT be used by a library intended for wider use. The standard and polite way for a library to behave is by error returns
答案1
得分: 13
是的,你可以按照你的建议进行操作。在标准包中,有一些情况下使用panic/recover来处理错误。官方的Go博客中提到:
一个真实的例子是Go标准库中的json包。它使用一组递归函数解码JSON编码的数据。当遇到格式错误的JSON时,解析器会调用panic来展开堆栈到顶层函数调用,然后从panic中恢复并返回适当的错误值(参见decode.go中decodeState类型的'error'和'unmarshal'方法)。
一些建议:
- 在正常情况下使用
error
。这应该是你的默认选择。 - 如果使用
panic
/recover
可以使你的代码更清晰、更简单(例如递归调用堆栈),那么可以在特定情况下使用它。 - 不要让包泄漏panic。在包内使用的panic应该在包内进行恢复,并作为错误返回。
- 从panic中恢复是稳定的。不用担心在恢复后继续执行。你可以在标准库中看到这种行为,比如
net/http
包在处理程序中从panic中恢复,以防止整个HTTP服务器在单个请求上发生panic时崩溃。
英文:
Yes, you can do what you suggest. There are some situations within the standard packages where panic/recover is used for handling errors. The official Go blog states:
> For a real-world example of panic and recover, see the json package
> from the Go standard library. It decodes JSON-encoded data with a set
> of recursive functions. When malformed JSON is encountered, the parser
> calls panic to unwind the stack to the top-level function call, which
> recovers from the panic and returns an appropriate error value (see
> the 'error' and 'unmarshal' methods of the decodeState type in
> decode.go).
Some pointers:
- Use
error
for your normal use cases. This should be your default. - If your code would get clearer and simpler by using a
panic
/recover
(such as with a recursive call stack), then use it for that particular case. - Never let a package leak panics. Panics used within a package should be recovered within the package and returned as an error.
- Recovering from a panic is stable. Don't worry about continuing execution after a recover. You can see such behavior in standard library such as with the
net/http
package which recovers from panics within handlers to prevent the entire http server to go crash when panicing on a single request.
答案2
得分: 1
通常大多数方法不会引发恐慌,而是返回一个错误,使用defer会有一些额外的开销。
所以是的,它确实可以工作,但是“正确”的/“go”的方式是返回一个错误,而不是使用恐慌/恢复。
英文:
Generally most methods won't panic, they will return an error instead, and there's a bit of an overhead of using defer.
So yes, it does work, but the "proper" / "go" way is to return an error instead of using panic / recover.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论