UP | HOME

条件判断

Table of Contents

if

前面的 find_max_and_min 函数里已经用到了 if 

现在介绍一个新的结构 if 。If 的语法格式如下:

if
    Condition 1 ->
	Action 1;
    Condition 2 ->
	Action 2;
    Condition 3 ->
	Action 3;
    Condition 4 ->
	Action 4
end

条件 的工作方式与 guard 一样,即 测试 并返回 成功 或者 失败

  • Erlang 从第一个条件开始测试一直到找到一个测试为真的分支,随后,执行该条件后的动作,且忽略其它在 end 前的条件与动作
  • 如果所有条件都测试失败,则会产生运行时错误
  • 一个测试恒为真的条件就是 true :它常用作 if 的最后一个条件,即当所有条件都测试失败时,则执行 true 后面的动作
注意:在 end 之前没有 “;”

下面这个例子说明了 if 的工作方式:

-module(conds).
-export([test_if/2]).

test_if(A, B) ->
    if 
        A == 5 ->
            io:format("A == 5~n", []),
            a_equals_5;
        B == 6 ->
            io:format("B == 6~n", []),
            b_equals_6;
        A == 2, B == 3 ->                      %That is A equals 2 and B equals 3
            io:format("A == 2, B == 3~n", []),
            a_equals_2_b_equals_3;
        A == 1 ; B == 7 ->                     %That is A equals 1 or B equals 7
            io:format("A == 1 ; B == 7~n", []),
            a_equals_1_or_b_equals_7
    end.

测试该程序:

8> conds:test_if(5,33). 
A == 5
a_equals_5

9> conds:test_if(33,6). 
B == 6
b_equals_6

10> conds:test_if(2,3).  
A == 2, B == 3
a_equals_2_b_equals_3

11> conds:test_if(1,33). 
A == 1 ; B == 7
a_equals_1_or_b_equals_7

12> conds:test_if(33,33).  
** exception error: no true branch found when evaluating an if expression
     in function  conds:test_if/2 (conds.erl, line 5)
注意:conds:test_if(33,33) 使得所有测试条件都失败,这将导致产生一个 if_clause 运行时错误

case

Erlang 中还有一种 case 结构。回想一下前面的 convert_length 函数:

convert_length({centimeter, X}) ->
    {inch, X / 2.54};
convert_length({inch, Y}) ->
    {centimeter, Y * 2.54}.

该函数也可以用 case 实现,如下所示:

-module(conds).
-export([convert_length/1]).

convert_length(Length) ->
    case Length of
        {centimeter, X} ->
            {inch, X / 2.54};
        {inch, Y} ->
            {centimeter, Y * 2.54}
    end.

无论是 case 还是 if 都有返回值

这也就是说,上面的例子中,case 语句要么返回 {inch,X/2.54} 要么返回 {centimeter,Y*2.54}。

case 语句也可以用 guard 子句 来实现。下面的例子可以帮助你分清二者。这个例子中,输入年份得到指定某月的天数。年份必须是已知的,因为闰年的二月有 29 天,所以必须根据年份才能判断二月的天数:

-module(conds).
-export([month_length/2]).

month_length(Year, Month) ->
    %% 被 400 整除的为闰年。
    %% 被 100 整除但不能被 400 整除的不是闰年。
    %% 被 4 整除但不能被 100 整除的为闰年。
    Leap = if
        trunc(Year / 400) * 400 == Year ->
            leap;
        trunc(Year / 100) * 100 == Year ->
            not_leap;
        trunc(Year / 4) * 4 == Year ->
            leap;
        true ->
            not_leap
    end,  
    case Month of
        sep -> 30;
        apr -> 30;
        jun -> 30;
        nov -> 30;
        feb when Leap == leap -> 29;
        feb -> 28;
        jan -> 31;
        mar -> 31;
        may -> 31;
        jul -> 31;
        aug -> 31;
        oct -> 31;
        dec -> 31
    end.

测试:

16> conds:month_length(2004,feb).  
29

17> conds:month_length(2003,feb).  
28

18> conds:month_length(1947,jan).  
31

19> conds:month_length(1947,jan1).  
** exception error: no case clause matching jan1
     in function  conds:month_length/2 (conds.erl, line 42)
从例子中可以看出:when是不一定需要返回值的!

Next:内置函数

Previous:列表操作

Home:顺序编程