try catch throw的本质
try
catch
本质就是 goto
, throw
本质就是 return
,没那么复杂。
你调用函数 foo()
bar()
,判断返回值,然后进行错误处理:
...result = foo(...);if (error_occurs(result)) {handle_foo_error...;release_resources...;}...result = bar(...);if (error_occurs(result)) {handle_bar_error...;release_resources...;}...
你嫌麻烦,因为有很多重复语句,比如释放资源,那么你可以用goto语句简化:
...result = foo(...);if (error_occurs(result)) {error = foo_error;goto catch;}...result = bar(...);if (error_occurs(result)) {error = bar_error;goto catch;}...
catch:if (error == foo_error) {handle_foo_error...;} else if (error == bar_error) {handle_bar_error...;}release_resources...;
你还嫌 goto
太老土,或者有没有一种高级版的 goto
可以从内层函数跳出来?那你可以用stdc函数 setjmp()
longjmp()
,不过这俩有bug,需慎用。而如果语言支持 try
catch
throw
,那么就简单多了:
try {result = foo(...); // foo_error在foo()里面throw...result = bar(...); // bar_error在bar()里面throw...
} catch (error) {if (error == foo_error) {handle_foo_error...;} else if (error == bar_error) {handle_bar_error...;}release_resources...;
}
我不喜欢那些让人云里雾里的术语,现在我就来告诉你们编译器/解释器是如何实现的:
首先,会标准化函数返回值,在其中嵌入一个隐藏的 success
布尔值标记, true
表示调用成功,返回值就是函数返回值, false
表示调用失败,那么返回值就是错误值(错误描述、堆栈信息…随便,反正都是值)。 throw
就是 return
,只不过会把 success
置为 false
。编译器/解释器发现如果函数调用处于 try
块里面,那么 success
为 false
的时候,就会 goto
到 catch
块,否则就打印返回值(就是错误值)并退出进程。
c是根本没有上述标准化套路;go lua有,但让你自行处理;三脚猫c++因为不是高级语言,无法在返回值里嵌入隐藏字段,用的是 setjmp()
longjmp()
?天晓得;至于java那种还把异常(错误?管它叫什么,反正就是返回值)各种分类,纯属吃饱撑的。
所以总结就是:本质都一样。随你喜好,想用就用,不想用就不用。