Erlang 函數、if、case、guardexpress
每節排版順序:僞代碼,說明文字,案例編程
%單一語句的的函數 function_name(Param1, Param2, ..., ParamN) -> Expression1, Expression2, ..., ExpressionN. %多語句的函數,其中每條語句的參數個數應該是同樣的 function_name(Param11, Param12, ..., Param1N) -> Expression11, Expression12, ..., Expression1N; function_name(Param21, Param22, ..., Param2N) -> Expression21, Expression22, ..., ExpressionN2; ... function_name(ParamN1, ParamN2, ..., ParamNN) -> ExpressionN1, ExpressionN2, ..., ExpressionNN;
函數的名稱是一個基元。一個函數的頭包括名字,隨後是一對括號,在裏面包含多個形式的參數或者沒有參數。在Erlang中,函數參數的數量叫作元數。使用箭頭(->)來分隔函數頭和函數主體。ide
Erlang函數是由分號分隔開的一個或者多個語句組成的,最後用句點來結束。每個語句都有一個頭部用來指按期望的參數模式,還有一個函數體,它由一個或多個以逗號分隔開的表達式組成,這些語句逐一按序執行,函數的返回值是最後一個表達式的結果。函數
%一個計算形狀面積的Erlang函數 area({ square, Side}) -> Side* Side; area({ circle, Radius}) -> math:pi() * Radius * Radius; area({ triangle, A, B, C}) -> S = ( A B C)/ 2, math:sqrt(S*(S-A)*(S-B)*(S-C)); area( Other) -> {error, invalid_ object}.
if Condition1 -> Expression11, Expression12, ...; Condition2 -> Expression21, Expression22, ...; Condition3 -> Expression31, Expression32, ...; ...; ConditionN -> ExpressionN1, ExpressionN2, ... end
Erlang是這樣工做的:先對Condition1求值,如值爲true,那麼將執行Expression11, Expression12, ...;並跳出該結構。若Condition1不成功,那麼就繼續對Condition2求值,以此類推,直到有條件成功。在if結構中,必需要有一個結果爲true,不然Erlang就會拋出一個異常。一般if語句的最後一個條件會是原子true,表示若是沒有匹配的條件的話,應該作什麼動做。測試
整個if表達式的結果是上面這一系列語句的返回值,它就是被執行的分支中最後執行語句的計算值。atom
%前面面代碼省略 func_common 就不貼出來了 IsEmail = func_common:is_email(LoginId), IsMobile = func_common:is_mobile(LoginId), IsNickname = func_common:is_nickname(LoginId), Conditions = if IsEmail -> [{email, LoginId}]; IsMobile -> [{mobile, LoginId}]; IsNickname -> [{nickname, LoginId}]; true -> [{nickname, LoginId}] end, Member = boss_db:find(member, Conditions), %後面代碼省略
%% if 語句 compare(A, B) -> if A > B -> io:format("~p > ~p~n", [A, B]); A < B -> io:format("~p < ~p~n", [A, B]); true -> io:format("~p = ~p~n", [A, B]) end.
case conditional-expression of Pattern1 -> Expression1; Pattern2 -> Expression2; ...; PatternN -> ExpressionN end
case結構依靠模式匹配來判斷應該執行哪些語句,它跟經過模式匹配來選擇執行函數很相似。不一樣的是,case不是把函數的真實參數和形式參數進行模式匹配,而是經過對一個表達式求值,而後對它的結果和一個由分號隔開的模式匹配列表進行匹配。code
使用的關鍵字是case、of和end。對conditional-expression求值,而後和Pattern1,...,PatternN進行匹配,直到第一個模式匹配成功。->符號把語句的模式或者頭部與由逗號分隔的表達式列表組成的主體分開。一旦模式匹配成功,選中的語句表達式就會一個個按次序執行,case結構的結果就是最後一個表達式的運行結果。orm
與函數定義同樣,case表達式的結果必須和一個模式匹配,不然將會獲得一個運行時錯誤。若是在最後的模式中有_或者未綁定變量,那麼它將匹配任何Erlang項元,這就如咱們在第2章中討論的catch-all語句同樣。catch-all語句不是必需的,事實上,不鼓勵把它做爲一種防錯性編程的形式來使用。ci
%% case 語句 compare3(A, B) -> case A > B of true -> io:format("~p > ~p~n", [A, B]); _ -> case A < B of true -> io:format("~p < ~p~n", [A, B]); _ -> io:format("~p = ~p~n", [A, B]) end end.
function_name(Param1, Param2, ..., ParamN) when Condition1 -> Expression1; function_name(Param1, Param2, ..., ParamN) when Condition2 -> Expression2; ... function_name(Param1, Param2, ..., ParamN) when ConditionN -> ExpressionN.
保護元( guard)是一個額外的限制條件,它應用於函數的case或者receive語句中。保護元應該放在「->」以前來分隔語句的主體和頭部。 保護元由when關鍵字和緊跟其後的一個保護元表達式組成。只有在模式匹配和保護元表達式求值結果爲基元true的狀況下,這個語句纔會執行。開發
單獨的保護元表達式可使用以下的結構得到:
保護元內置函數致使運行時錯誤的保護元子表達式被視爲返回false。
<b>保護元能夠是測試的複雜組合,但並不容許引用任何用戶自定義的函數。 </b>
規定開發人員不能用語句實現本身的保護元函數的緣由是要限制它們的操做,從而確保保護元語句不會產生邊界效應。在找到一個成功的語句執行以前,將會執行全部的測試保護元語句,這意味着假設在一個保護元裏調用一個io:format,若是它失敗了,你仍是會看到打印輸出,即便這個語句沒有被選中執行。
<b>注意:</b>在Erlang語言中有一些類型測試內置函數的老版本,它們的名稱就是類型名稱:atom/1和integer/1等。不推薦使用這些內置函數,由於它們已通過時,它們的存在只是爲了向後兼容。新的保護元函數是is_atom/1和is_integer/1等。
Erlang容許保護元進行簡單的邏輯組合,以不一樣的方式實現:
my_add(X, Y) when not( ((X>Y) or not(is_atom(X))) and (is_atom(Y) or ( X==3.4)) ) -> X+Y.
max(X, Y) when X > Y -> X; max(X, Y) -> Y.
factorial(N) when N>0 -> N * factorial(N-1); factorial(0) -> 1.
-module(compare). -export([compare/2, compare2/2, compare3/2]). %% guard 語句 compare2(A, B) when A > B -> io:format("~p > ~p~n", [A, B]); compare2(A, B) when A < B -> io:format("~p < ~p~n", [A, B]); compare2(A, B) -> io:format("~p = ~p~n", [A, B]).