首页 > 代码库 > [Erl_Question02] 那些经历过的Erlang小坑(持续更新)
[Erl_Question02] 那些经历过的Erlang小坑(持续更新)
1. 保护式(guard)中如果出错,不会报错,只会返回false!
case 1=:1 of true when not erlang:length(t) =:= 1 orelse true -> ok; _ -> error end.Result is: error
保护式中对t (atom) 求length会出错,本应crash掉,但因为在保护式中,默认出错后结束此保护式计算并返回false,这也是为什么保护式不接受复杂的函数,只能用erlang的bif来做的原因之一。
2. try catch 时如果不写catch类型,默认为throw类型!
try_catch(Value) -> try case Value of error -> erlang:error({error,plz_catch_me}); throw -> erlang:throw({throw,oh_get_you}); exit -> erlang:exit({exit,sorry_by_mistake}) end catch T -> T end.
Result :
所以最好是:明确: Catch throw:T –> {throw,T}; error:T –> {error,T}; exit:T –> {exit,T} end.
3. 在保护式中使用erlang:length/1要小心再小心!(要遍历列表,时间长度不定)
%%写成这样的耗时与列表长度成平方比:Do not do this foo(List) when lenght(List) >0 -> do_something; foo(_) -> done. %%使用匹配模式来做可做到任意长度断定 better([One]) -> do_something_one(); better([One,Two]) -> do_something_two(); better([one,Two|_]) -> do_something_big(); better([]) -> do_something_empty() end.
Tip: 如果要判定List是一个非空List 可用 case List of [_|_] –> do_something(); _ –> done end.
4. ++只是lists:append/2的一个别名:如果要用一定要确定 ShortList++LongList !(可记为长短的反义短长…每次用他我都会条件反射想一下)
%% DO NOT DO naive_reverse([H|T]) -> naive_reverse(T)++[H]; naive_reverse([]) -> [].
which is the most inefficient way there is to reverse a list. Since the ++ operator copies its left operand, the result will be copied again and again and again... leading to quadratic complexity.
这是最没效率去反转一个list,”++“会复制左边的元素,这个会使复制多次,导致平方倍的复杂度。
但是另一方面:下面这种用法就好了:
%% OK naive_but_ok_reverse([H|T], Acc) -> naive_but_ok_reverse(T, [H]++Acc); naive_but_ok_reverse([], Acc) -> Acc.
这并不是一个是非常坏的尝试,每个列表元素只被copy一次,那增长的Acc是在++的右边的,他不会每次都被copy的
当然,最佳实践还是下面这种:
%% Best Do vanilla_reverse([H|T], Acc) -> vanilla_reverse(T, [H|Acc]); vanilla_reverse([], Acc) -> Acc.
这比上面的还要高效一点点,你根本不用去建造一个list元素,直接copy他就可以了(或者:如果编译器不把[H]++Acc重写为[H|Acc] ,那就更高效啦)。
5. receive 和case的区别很大,虽然写法类似:
case_test(Value) -> case Value of 1 -> ok; 2 -> error end. receive_test(Value)when Value>2 -> PID = spawn(fun () -> receive {msg,1} -> ok; {msg,2} -> error end end), [begin PID ! {msg,ValueT} end ||ValueT<-lists:seq(3,Value)], PID.
Result:
从上面可以看出:
5.1 case如果没有匹配就会出错;
5.1 recieve 会在没有匹配消息时阻塞,只要信箱中没有匹配消息,就会在等待期间挂起,=有新消息到时才会被唤醒,每次执行时,receive会先检查最老的消息(位于队列头部),像在case表达式中那样尝试匹配,如果找不到,就会继续下一消息,如果与当前匹配成功,且保护式成立(如果有),此消息就会被移出信箱,同时子句对应的正文会被执行,如果一直没找到合适消息就会一直等待至超时(如果有的话,after Times).