将”将恐慌/恢复视为抛出/捕获”视为错误吗?

huangapple go评论63阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2014年6月6日 06:03:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/24070922.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定