Erlang if、case、guard和函數

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 結構

僞代碼

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 結構

僞代碼

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.

guard 結構

僞代碼

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的狀況下,這個語句纔會執行。開發

單獨的保護元表達式可使用以下的結構得到:

  • 約束變量·Erlang常量的數據值,包括數字、基元、元組和列表等
  • 類型測試語句,好比is_binary、is_atom、is_boolean和is_tuple等
  • 第2章中所列出的項元比較運算符==、=/=、<、>等
  • 第2章中所列出的使用算術運算符組成的算術表達式
  • 第2章中所列出的布爾表達式

保護元內置函數致使運行時錯誤的保護元子表達式被視爲返回false。

<b>保護元能夠是測試的複雜組合,但並不容許引用任何用戶自定義的函數。 </b>

規定開發人員不能用語句實現本身的保護元函數的緣由是要限制它們的操做,從而確保保護元語句不會產生邊界效應。在找到一個成功的語句執行以前,將會執行全部的測試保護元語句,這意味着假設在一個保護元裏調用一個io:format,若是它失敗了,你仍是會看到打印輸出,即便這個語句沒有被選中執行。

<b>注意:</b>在Erlang語言中有一些類型測試內置函數的老版本,它們的名稱就是類型名稱:atom/1和integer/1等。不推薦使用這些內置函數,由於它們已通過時,它們的存在只是爲了向後兼容。新的保護元函數是is_atom/1和is_integer/1等。

Erlang容許保護元進行簡單的邏輯組合,以不一樣的方式實現:

  • 用逗號(,)來分隔各個保護元語句,這是一種邏輯乘,所以只有在串行序列中全部表達式的值都是true的時候,它的結果才爲true。
  • 用分號(;)來分隔各個保護元語句,這是一種邏輯加(或者其實是逗號分隔的邏輯乘),若是有一個表達式的值爲true,則它的結果就是true。

案例

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]).
相關文章
相關標籤/搜索