1. error/1

主要是系统用来定义内部错误的: Erlang内建的run time error 一共有10种:

function_clause/case_clause/if_clause/badmatch/badarg/undef/badarith/badfun/badarity/system_limit, 比如:

 1> erlang:binary_to_list(1).
** exception error: bad argument
in function binary_to_list/1
called as binary_to_list(1)

这上面就是触发了error/1,我们也可以手动触发一下。

 2> erlang:error(badarg).
** exception error: bad argument        

注意到erlang直接把badarg这种内建的error转成更详细的bad argument,

更进一步,我们也可以使用error/1定义自己的错误

3> erlang:error("this is my own error").
** exception error: "this is my own error"

这一次,自定义的错就没有被erlang shell认出来。

2. exit/1 exit/2

exit有internal exits 和 external exits的区别,我们可以使用exit(Pid,Reason)让别一个进程退出。

exit/1和error/1非常相似,很多时候可以通用,便是exit语境是退出,更适合于进程退出的情况,还有一个区别就是

exit/1不会带调用的stack trace信息(方便让其它进程退出时不用带非常大的调用信息,更轻量)。但是error/1会带。

4> catch exit(test).
{'EXIT',test}
5> catch error(test).
{'EXIT',{test,[{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,674}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,431}]},
{shell,exprs,7,[{file,"shell.erl"},{line,686}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}} 

3. throw/1

throw/1 它最常用配合 try...of catch 处理嵌套case(可以快速跳出),它所携带的信息最少(比exit/1还少一个'EXIT'):

6> catch throw(2+2).
4
7> catch 2+2
4     

上面2个case用的catch,都区分不出结果是throw出来的,还是正常计算得到的结果,所以这也是推荐使用try .. of catch的原因:

8> try throw(2+2) of
8> V -> {ok, V}
8> catch
8> throw:V -> {error, V}
8> end.
{error,4} 

4. 总结

进程退出使用exit/1或exit/2, 想快速跳出recursion或快速跳回Top-Level函数时用throw/1,尽量不要使用error/1,

如果需要得到调用的stack trace信息,可以自己显式的调用erlang:get_stacktrace().得到当前进程最新一次Exception时的的stacktrace。

5. 扩展(gen_server中的几种退出进程方法比较)

 我们在gen_server中安全有5种退出方法,
5.1. 在init不成功时返回{stop, Reason} 退出;
5.2. 处理消息出错,或正常退出时返回{stop, Reason, NewState});
5.3. 使用exit直接退出进程;
5.4. 使用throw退出进程;
5.5. 使用error退出进程(由于我们前面讲了error主要用于定义内部错误,所以不推荐使用)。

前两种是显而易见的,关键是后三种方式退出与前者的区别。
先来理一理{stop, Reason, NewState},直接exit, 直接throw三者的区别。
try_dispatch(Mod, Func, Msg, State) ->
try
{ok, Mod:Func(Msg, State)}
catch
throw:R ->
{ok, R};
error:R ->
Stacktrace = erlang:get_stacktrace(),
{'EXIT', {R, Stacktrace}, {R, Stacktrace}};
exit:R ->
Stacktrace = erlang:get_stacktrace(),
{'EXIT', R, {R, Stacktrace}}
end.

使用stop就是正常退出,不带stack trace信息(他本来就没有crash,也没有stack信息)

使用exit退出,它带了stack trace信息。

使用throw退出,它没有带stack trace信息,且要throw出来的term要是符合gen_server标准,比如
{noreply, NewState}
{reply, ok, NewState}
{stop, normal, NewState}

  

明白了以上区别,就很容易选择了:
1.exit也是用于不可预期的错误,需要返回它的stack trace信息用来记录,所以不推荐在gen_server中主动调用exit;
2.throw可以快速回应本次消息的处理,简化代码的嵌套case逻辑,不过要注意,throw出来的一定是一个符合gen_server标准的东西,不然会报错。
3.正常可预期的逻辑都都使用{stop,Reason, NewState}处理。 

我们再深入一点:
当我们stop时的Reason不是 normal | shutdown | {shutdown,term()} 时会在kernel log中打印日志
 

Notice that for any other reason than normal, shutdown, or {shutdown,Term}, the gen_server process is assumed to terminate because of an error and an error report is issued using error_logger:format/2.

比如这样:
=ERROR REPORT==== 31-Oct-2016::15:10:44 ===
** Generic server test_throw_exit terminating
** Last message in was go
** When Server state == {state}
** Reason for termination ==
** not_shutdown_term

所以,如果我们在正常退出或shutdown时不需要那一列烦人的log,就把reason定义为三者中的一种就行了。

具体源码可见: https://github.com/erlang/otp/blob/maint/lib/stdlib/src/gen_server.erl#L809

总结:
1. 在gen_server中正常退出,请回复{stop, Reason, NewState},
2. 如果是要快速结束此次消息的退出可以使用throw(term()),其中term()符合gen_server规范(和正常返回的值一样),
3. 正常逻辑里面不推荐使用exit/error来处理,分携带多余的stack trace信息。 
 

6. 参考资料:

  Erlang官方文档:http://erlang.org/doc/reference_manual/errors.html

Learnyousomeerlang关于Exceptions的介绍: http://learnyousomeerlang.com/errors-and-exceptions

[Erlang37]error/1 exit/1 exit/2 throw/1的区别的更多相关文章

  1. error adding symbols: DSO missing from command line collect2: error: ld returned 1 exit status

    Windows服务器Azure云编译安装MariaDB教程 www.111cn.net 编辑:future 来源:转载 安装MariaDB数据库最多用于linux系统中了,下文给各位介绍在Window ...

  2. svn Error: post-commit hook failed (exit code 127) with output

    Command: Commit Modified: C:\Users\xsdff\Desktop\project\index.html Sending content: C:\Users\xsdff\ ...

  3. error: ld returned 1 exit status 和 error:undefined reference

    undefined reference 往往是链接时出现错误,无法解析引用.这篇文章总结的很好undefined reference问题总结 error: ld returned 1 exit sta ...

  4. docker pull报错failed to register layer: Error processing tar file(exit status 1): open permission denied

    近来在一个云主机上操作docker pull,报错如下: failed to register layer: Error processing ): open /etc/init.d/hwclock. ...

  5. Arduino上“Collect2.exe: error: ld returned 5 exit status”错误的解决方法

    1.运行环境 Windows xp; Arduino1.6.11 IDE. 2.问题 在Arduino编译时,经常出现如下的错误: collect2.exe: error: ld returned 5 ...

  6. docker mac 命令行登录报错处理 : Error saving credentials: error storing credentials - err: exit status 1

    参考:https://blog.csdn.net/xufwind/article/details/88756557 比较新版本的docker命令行登录会出现以下错误: Error saving cre ...

  7. moc_XXXX.o:(.data.rel.ro._ZTI12CalculatorUI[_ZTI12CalculatorUI]+0x10): undefined reference to `typeinfo for QWidget' collect2: error: ld returned 1 exit status make: *** [Makefile:144: myCalculator]

    main.cpp:(.text.startup+0x22): undefined reference to `QApplication::QApplication(int&, char**, ...

  8. DevC++ 报错[Error] Id returned 1 exit status

    DevC++ 报错[Error] Id returned 1 exit status 起因 学校机房的计算机总是二次编译总是报错 报错提示 [Error] Id returned 1 exit sta ...

  9. Dev C++编写C/C++程序 出现[Error] ld returned 1 exit status报错分析及解决

    debug系列第一弹,不知道大家写程序的时候是不是都遇到过如题的报错. 我本人是经常遇到这行熟悉的令人不知所措的报错,可能是我太笨了 有时候百度无果也差不到原因,那就汇总一下目前我遇到的情况吧--持续 ...

随机推荐

  1. ubuntu修改源列表sourcelist的方法

    1.备份源列表 sudo cp /etc/apt/sources.list /etc/apt/sources.list_backup 2.找到对应版本的源,可以在以下界面当中找到,主要版本要对.htt ...

  2. IOS字典NSDictionary与NSMutableDictionary知识点

    字典中的元素是以键值对的形式存储的,键值对的键和值,都是任意的对象,但是键往往使用字符串,字典存储对象的地址没有顺序,字典的遍历分为:键的遍历和值的遍历,字典与数组的区别:数组讲究顺序,而字典可以快速 ...

  3. swift基础一

    // swift中导入类库使用import,不再使用<>和"" import Foundation // 输出 print("Hello, World!&qu ...

  4. C语言的判断语句

    // // main.c // homeWork1222 //// #include <stdio.h> int main(int argc, const char * argv[]) { ...

  5. Swift Standard Library: Documented and undocumented built-in functions in the Swift standard library – the complete list with all 74 functions

    Swift has 74 built-in functions but only seven of them are documented in the Swift book (“The Swift ...

  6. [转]Designing a User Interface

    UI design can be divided into three essential elements : functionality, aesthetics, and performance. ...

  7. IDO分享 | 如何在centos下安装OpenCMS

    本次的opencms环境是在两台机器上搭建的. 一台服务器安装mySQL, 一台服务器安装jdk.tomcat.opencms.也可以将jdk.mySQL.tomcat.opencms安装在同一个机器 ...

  8. INFORMATICA 的部署实施 MTP&MTS

    软件开发的一般都有三个环境,开发环境,用户接受度测试环境,生产环境.我最近实施了从开发环境到生产环境的部署工作,在此跟大家分享一下. 大概步骤如下: 1 备份生产环境INFORMATICA 知识库  ...

  9. Effective Java 02 Consider a builder when faced with many constructor parameters

    Advantage It simulates named optional parameters which is easily used to client API. Detect the inva ...

  10. SpringMVC 返回 html 视图页面,SpringMVC与Servlet,Servlet重定向与转发

    1. SpringMVC与Servlet的关系 SpringMVC框架是建立在Servlet之上的,提供各种功能,各种封装,各种方便的同时,它一点儿也没有限制Servlet,我们完全可以在Spring ...