标签:
任何语言在使用中都会遇到这样那样的问题,erlang也是。这里整理下我遇到的一些问题,避免继续踩坑。说实话,“防坑指南”这个标题有点过于标新立异,不过还是希望能引起重视,避免在实际开发中重复犯这些问题。
‘--‘ 运算
1> [1,2,3,4] -- [1] -- [2].
[2,3,4]
算是erlang经典的问题了。这是从后面算起的,先算 [1] -- [2] ,得到 [1] 后被 [1,2,3,4] --,最后得到 [2,3,4]
如果是 ++ 也是一样的,从后面开始算起,只不过是 ++ 从前面算或者从后面开始算结果都一样的。
2> [1,2,3,2] -- [2].
[1,3,2]
这种情况也要注意,只会减去遇到的第一个元素。
erlang:function_exported
这个接口是用来检查模块函数是否导出,但是,如果模块没加载过,这个函数返回值就是false
3> erlang:function_exported(odbc,start,0).
false
4> odbc:start().
ok
5> erlang:function_exported(odbc,start,0).
true
erlang:list_to_binary
如果参数是多层嵌套结构,就会被扁平化掉,使用 binary_to_list 不能转成原来的数据,也就是不可逆的。
6> list_to_binary([1,2,[3,4],5]) .
<<1,2,3,4,5>>
如果想可逆,可以使用 erlang:term_to_binary
7> binary_to_term(term_to_binary([1,2,[3,4],5])).
[1,2,[3,4],5]
try... catch
try1(ErrType) -> try case ErrType of error -> erlang:error(error); exit -> erlang:exit (exit); throw -> erlang:throw(throw) end catch Err -> Err end. |
8> test:try1(error).
** exception error: error
in function test:try1/1 (test.erl, line 7)
9> test:try1(exit).
** exception exit: exit
in function test:try1/1 (test.erl, line 8)
10> test:try1(throw).
throw
以上结果只有 throw可以匹配,如果想要全部匹配到要改写这个函数:
try1(ErrType) -> try case ErrType of error -> erlang:error(error); exit -> erlang:exit (exit); throw -> erlang:throw(throw) end catch _:Err -> Err end. |
断言(guard)
check(A) when length(A) > 9 -> error; check(_) -> ok. |
检查list长度,但如果传入的数据不是list,结果又会怎样?
11> test:check(hack).
ok
在 guard 模式下,原本会抛出异常的代码就不会报错了,而是结束当前计算并返回false。
顺道说下以下几种情况:
check1(A) when length(A) > 9 ; true-> error; check1(_) -> ok. check2(A) when length(A) > 9 orelse true-> error; check2(_) -> ok. check3(A) when length(A) > 9 , true-> error; check3(_) -> ok. check4(A) when length(A) > 9 andalso true-> error; check4(_) -> ok. |
12> test:check1(hack).
error
13> test:check2(hack).
ok
14> test:check3(hack).
ok
15> test:check4(hack).
ok
如此可见,orelse 和 ‘,‘ 运算还是有区别的。
io_lib:char_list
R15下: Eshell V5.9.3.1 (abort with ^G) 1> io_lib:char_list([10100,10600,20100]). false
R16下: Eshell V5.10.1 (abort with ^G) 1> io_lib:char_list([10100,10600,20100]). true |
结果是截然相反,可想而知,如果写了这段代码,换个版本就可能运行有问题了。erlang的版本过渡还是有点粗放。
gen_server
gen_server在跨节点下发消息使用 noconnect ,这是正确的选择,可以参考这篇文章 但是,gen_server:cast 使用中可能会有问题。以下是 cast 的实现代码:
do_cast(Dest, Request) -> do_send(Dest, cast_msg(Request)), ok. do_send(Dest, Msg) -> case catch erlang:send(Dest, Msg, [noconnect]) of noconnect -> spawn(erlang, send, [Dest,Msg]); Other -> Other end. |
当连接不成功时,cast还会新起一个进程去发消息。这就算了,而且不带 noconnect,就是说还会尽最大可能把消息发出去。本来这里是没有不好,但是一般使用gen_server不会意识到有这个问题。在网络不理想的情况,就会莫名其妙多了很多进程,进程本身有最大数量限制。另外,消息发不出去,还是堆积在内存中。
16> hack >1. true 17> [] > 1. true 18> [] > {a,b,c}. true |
比较公式为:number < atom < reference < fun < port < pid < tuple < list < bit string
系统限制
这些有点老生常谈了,不过开发中还是要注意。
1. mnesia或dets有2G限制(无法定制)
2. ets表最大数量默认1400(可用 ERL_MAX_ETS_TABLES 定制)
3. 原子最大数量默认 1048576 (可用 +t 定制)
4. 进程最大数量默认 32768 (可用 +P 定制, 范围1024-134217727)
5. 端口/文件句柄最大数量默认 16384 (可用 +Q 定制, 范围1024-134217727)
参考:http://blog.csdn.net/mycwq/article/details/43775285
最后,这个标题确实有点标新立异
erlang开发经验谈:防坑指南
标签:
原文地址:http://blog.csdn.net/mycwq/article/details/43775285