我知道惯例说要限制panic/recover的使用,但运行时是否也会限制它们的使用方式,使它们不能像C++中的throw/catch一样被广泛使用?
一些历史:
在Go语言的早期版本(1.0之前),没有recover()
。调用panic()
会终止应用程序,没有任何方法可以停止它。
我找到了最初讨论添加recover()
的帖子,你可以在golang-nuts讨论区阅读:
注意:该讨论始于2010年3月25日,非常冗长(6页150个帖子)。
最终,它于2010-03-30被添加:
This release contains three language changes:panic
and recover
, which are used for reporting and recovering from failures, have been added to the specification. For more information, please refer to http://golang.org/doc/go_spec.html#Handling_panics.panicln
has been removed, and panic
is now a function that takes only one argument.http://blog.golang.org/defer-panic-and-recover
http://dave.cheney.net/2012/01/18/why-go-gets-exceptions-right
https://golang.org/doc/faq#exceptions
http://evanfarrer.blogspot.co.uk/2012/05/go-programming-language-has-exceptions.html
panic
显然是滥用该功能。但问题在于,以那种方式滥用它比检查标志等方式使代码更可读/可理解和可维护。放弃一些纯粹性并在可维护性方面取胜比反过来要好;-) - kostix我认为你的问题是由于你持有的心理模型造成的,这种心理模型是由流行的主流语言(如Java、C++、C#、PHP等)灌输的,它们简单地处理了异常。
事实上,异常本身并不是一个错误的概念,但滥用它们来处理现实中并非异常的情况是错误的。我个人最讨厌的是Java的文件系统处理API(以及几乎照搬Java的.NET):如果文件不存在,为什么打开文件失败会导致异常呢?文件系统是一种固有的竞争性媒介,并且被指定为具有竞争性,因此在打开文件进行读取之前,确保文件存在的唯一正确方法就是打开它,然后检查“文件不存在”错误:文件不存在的情况根本不是异常情况。
因此,Go明确区分了异常情况和普通的正常错误。Go维护的处理错误的立场的座右铭是“错误是值”,因此预期的普通错误被视为值来处理,而panic()
用于处理异常情况。以下是一个很好的简单示例:
尝试对nil
指针进行解引用会导致panic
。
原因:您的代码继续尝试对不指向任何值的指针进行解引用。紧随其后的代码明确期望该值可用,作为解引用操作的结果。因此,控制流不能以任何明智的方式正常进行,这就是为什么这是一个异常情况:在正确的程序中,无法发生对nil
指针的解引用。
TCP流的远程端突然关闭了它的流一侧,下一次尝试从它读取时会导致错误。
这是非常正常的情况:人们不能合理地期望TCP会很稳定:网络中断、数据包丢失、意外停电确实会发生,我们必须为远程同行意外流关闭做好准备。
panic
来从深层嵌套的处理循环中跳出,并在执行recover
的位置上检查它。我认为原因在于并发模型。Go语言天生就是高度并发的语言,其核心语法也是如此。当某些计算局部化到并发进程失败时,但整个系统仍然可以正常工作,这种情况可以被视为正常。在我看来,panic和recover是关于故障处理而不是异常处理。
因为这样更强大,可以创建更具弹性的程序。
在 C 中,您无法从 NULL 指针引用中恢复。
在 Go 中,您可以使用 recover
捕获它。
例如,在 Go 中创建一个 HTTP 服务器,可以捕获处理请求时的 NULL 指针引用并返回错误 500,而不是使整个服务器崩溃。