转载请注明,来自:http://blog.csdn.net/skyman_2001
Erlang的异常处理一般是try catch,虽然erlang比较推荐Let It Crash,不怎么推荐防御式编程,但try catch在以下两个方面还是很有用的:
1. 处理用户输入,因为你不能确保输入的数据的正确性,这时为了稳定性,可以使用try catch(比如网游服务器,稳定性是很重要的);
2. 嵌套很多层的函数,如果通过一层一层的返回返回值写起来比较麻烦,这个时候可以使用try catch,里面的函数可以通过throw来返回到顶层函数。网游中的一个典型的例子就是某个操作的条件检查(比如学习技能、使用物品),会有很多条件,用throw的方法会使代码简练很多。erlang自己库里也有这样的例子,比如ssl库:
new_connect(Address, Port, Options, Timeout) when is_list(Options) ->
try handle_options(Options, client) of
{ok, Config} ->
do_new_connect(Address,Port,Config,Timeout)
catch
throw:Error ->
Error
end.
handle_options(Opts0, _Role) ->
...
VerifyNoneFun = handle_option(verify_fun, Opts, DefaultVerifyNoneFun),
UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false),
UserVerifyFun = handle_option(verify_fun, Opts, undefined),
CaCerts = handle_option(cacerts, Opts, undefined),
{Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun} =
%% Handle 0, 1, 2 for backwards compatibility
case proplists:get_value(verify, Opts, verify_none) of
0 ->
{verify_none, false,
ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
1 ->
{verify_peer, false,
ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
2 ->
{verify_peer, true,
ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
verify_none ->
{verify_none, false,
ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
verify_peer ->
{verify_peer, UserFailIfNoPeerCert,
ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
Value ->
throw({error, {eoptions, {verify, Value}}})
end,
...
{ok, ...}.
handle_option(OptionName, Opts, Default) ->
validate_option(OptionName,
proplists:get_value(OptionName, Opts, Default)).
validate_option(ciphers, Value) when is_list(Value) ->
Version = ssl_record:highest_protocol_version([]),
try cipher_suites(Version, Value)
catch
exit:_ ->
throw({error, {eoptions, {ciphers, Value}}});
error:_->
throw({error, {eoptions, {ciphers, Value}}})
end;
...
从上面代码可以发现,在顶层函数里有try catch,如果是正确的就做进一步处理,如果catch到throw异常,则返回该异常信息(注意这里用throw:Error表示只处理throw异常,因为嵌套函数里的错误的返回是通过throw/1来抛出的),嵌套函数如果有错就直接throw/1,这样就省去一层一层返回返回值的麻烦了。
关于异常处理的一个通常做法是:在捕获到异常时将异常信息写到日志中,方便程序的分析和修复。异常和日志都是保证软件产品质量的重要手段!
还有一个要注意的点是:try块是不能构成尾递归的,erlang虚拟机必须始终保持它的引用,以防异常出现,所以如果在try块调用递归函数会造成大量内存消耗。
参考文献:
Errors and Exceptions:http://learnyousomeerlang.com/errors-and-exceptions