1. 保護式(guard)中若是出錯,不會報錯,只會返回false!html
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來作的緣由之一。node
2. try catch 時若是不寫catch類型,默認爲throw類型!shell
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 :cookie
因此最好是:明確: Catch throw:T –> {throw,T}; error:T –> {error,T}; exit:T –> {exit,T} end.app
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.oop
4. ++只是lists:append/2的一個別名:若是要用必定要肯定 ShortList++LongList !(可記爲長短的反義短長…每次用他我都會條件反射想一下)this
%% 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.atom
這是最沒效率去反轉一個list,」++「會複製左邊的元素,這個會使複製屢次,致使平方倍的複雜度。spa
可是另外一方面:下面這種用法就行了:
%% 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).
6. erl 用-noshell –noinput 啓動一個node時,看不到,又不能輸入怎麼調試?用-remsh參數
>erl -name foo@127.0.0.1 -setcookie 123456 -noshell -noinput >erl -name bob@127.0.0.1 -setcookie 123456 -remsh foo@127.0.0.1 %%注意起的節點叫foo哦,不是bob了! foo@127.0.0.1> nodes(). foo@127.0.0.1>['bob@127.0.0.1'] foo@127.0.0.1>node(). foo@127.0.0.1>'foo@127.0.0.1'
這裏的坑在於:
6.1 在remote出來的節點上調用q(),2個節點都會退出!好可怕,全部最好把q()這個函數在user_default.erl裏面重寫,讓他不要執行init: stop().
6.2 window下要用werl 代替erl;
6.3 erl支持自定義參數,好比你寫erl –rmsh test 也是不會報錯的,若是不當心寫錯了,就會查很久……..
Tip: 已 起A,B二個節點,要用A 控制B,能夠在A中使用Ctrl+G r NodeA j 2操做 具體見:Learn some erlang remote shell.
7.若是有一個ArgList 是:從不可知道的地方傳過來是這樣子:」[test1,test2,test3]」,要怎麼使用才能動態執行?
場景:知道方法調用的方法:Method 使用 erlang:apply(Module,Method,ArgList)調用產生結果,這時的ArgList是不符合格式:
%% String = "[test1,test2,4]."注意最後面的結束小句號! string_to_args(String) -> {ok, Scan1, _} = erl_scan:string(String), {ok,P}=erl_parse:parse_exprs(Scan1), {value,Value,[]} = erl_eval:exprs(P, []), Value.
以上合適List中全部的參數都是綁定的:,若是是有Test1這樣的變量,我也沒試過,還沒遇到這種需求
8. erl 啓動參數能夠本身定義:如
>erl -test erlang1 -test hello -test1 test1 >init:get_argument(test). {ok,[["erlang1"],["hello"]] >init:get_arguments(). [{root,["C:\\Program Files\\erl6.0"]}, {progname,["erl"]}, {home,["C:\\Users\\**"]}, {test,["erlang1"]}, {test,["hello"]}]
8.1 不要把參數定義爲string了:好比 「hello world」
8.2 若是這個是啓動application啓動用的,就不要期望用這個自定義的參數了,用config定義吧
9.使用RPC時必定要記得你是在distributed的,時刻關注你在那個進程!
好比:把rpc:call放在loop裏面和外面會獲得不同的效率反饋,如下這例子的結果是等價的,可是第一種會發出不少的call,第二種只有一個call.
%%Example - Bad [rpc:call(node, ets, lookup, [table, K]) || K <- ListOfKeys]. %%Example - Good rpc:call(node, ?MODULE, get_data, [ListOfKeys, []]). get_data([], Out) -> lists:reverse(Out); get_data([K|ListOfKeys], Out) -> get_data(ListOfKeys, [ets:lookup(table,K)|Out]).
同理你能夠本身改一下:[gen_server:call(Pid,{func,Fun})||Fun<- FunList].
總之要能一次發消息處理的就不要屢次發啦.
10 不要構造超極大的terms(或者你不可控制大小的terms).
具體就是若是要遍歷ets裏面全部的元素,用ets:tab2list/1得出來的結果可能什麼很是大,這可怎麼辦啊!
%% 一次性也出全部元素:不要這樣子作 bad_traverse_to_print() -> [begin print(Person) end||Person <- ets:tab2list(person)], ok. %%從第一個一直遍歷到最後一個:數據要從erts內部搬到process 當ets很大的時候就效率低 good_traverse_to_print() -> good_traverse_to_print2(ets:first(person)). good_traverse_to_print2('$end_of_table') -> ok; good_traverse_to_print2(Key) -> [Person] = ets:lookup(person,Key), print(Person), good_traverse_to_print2(ets:next(person,Key)). %%分頁:最佳實踐使用ets:select match MatchSpec:ets內部實現了把matchspec編譯成opcode 而後eval的時候把須要的數據才拷貝到process去 大大減小了數據量 best_traverse_to_print() -> case ets:match(person,'$1',10) of {PersonList,'$end_of_table'} -> [begin print(Person) end|| [Person] <- PersonList]; {PersonList,Key} -> [begin print(Person) end|| [Person] <- PersonList], best_traverse_to_print2(Key) end, ok. best_traverse_to_print2(Key) -> case ets:match(Key) of {PersonList,'$end_of_table'} -> [begin print(Person) end|| [Person] <- PersonList]; {PersonList,Key2} -> [begin print(Person) end|| [Person] <- PersonList], best_traverse_to_print2(Key2) end. print(Person) -> io:format("Name~p Phone:~p~n",[Person#person.name, Person#person.phone]), ok.