《Learn You Some Erlang for Great Good!》的学习笔记(五)

     介绍了简单的模块之后,我们将要进一步的了解一下函数中的语法。首先,我们就来看看,函数中的模式匹配。如下所示:

greet(male, Name) ->
    io:format("Hello, Mr. ~s!", [Name]);
greet(female, Name) ->
    io:format("Hello, Mrs. ~s!", [Name]);
greet(_, Name) ->
    io:format("Hello, ~s!", [Name]).

      函数很容易理解,各个分支之间,以分号隔开。你只需要指定性别和姓名,并调用greet方法,即可进入相应的分支函数,如hello:greet(male, Jiang)。而如果没有任何匹配的函数,erlang将会抛出异常。
再看一个更高级的函数:

valid_time({Date = {Y,M,D}, Time = {H,Min,S}}) ->
    io:format("The Date tuple (~p) says today is: ~p/~p/~p,~n",[Date,Y,M,D]),
    io:format("The time tuple (~p) indicates: ~p:~p:~p.~n", [Time,H,Min,S]);
valid_time(_) ->
    io:format("Stop feeding me wrong data!~n").

运行的结果如下:

4> c(functions).

{ok, functions}

5> functions:valid_time({{2013,12,12},{09,04,43}}).

The Date tuple ({2013,9,6}) says today is: 2013/9/6, The time tuple ({9,4,43}) indicates: 9:4:43.

ok6> functions:valid_time({{2013,09,06},{09,04}}).

Stop feeding me wrong data!ok 

在此可以注意到,在函数头中,我们也使用了模式匹配符=,进而解析出元组中的年、月、日。
      然而至此,我们也可以看到,我们定义的函数不仅可以匹配元组,还可以匹配任何数据类型,并没有任何的限制。为了解决这个问题,我们使用guards来限制函数的入参:
如果你需要写一个函数来验证一个人的年龄是否符合考驾照的要求,比如法定年龄是16岁以上、104岁以下,以现有的学习内容来看,你可能会采用枚举法,从1开始一直匹配。有了Guards的话,你就可以轻松的描述出这一需求:

right_age(X) when X >= 16, X =< 104 ->
    true;
right_age(_) ->
    false.

语法很简单,需要注意的是,在Guards中,“,”逗号和andalso类似,而“;”分号和orelse类似,因此上面的表达是也可以写成:

right_age(X) when X < 16;X > 104 ->
    false;
right_age(_) ->
    true.

同时为了进一步限制,只允许接收整数:

right_age(X) when is_integer(X) , X >= 16, X =< 104 ->
    true;
right_age(X) when is_integer(X) ->
    false.

但是比较遗憾的一点是,目前guards不接受你自定义的函数。至于原因就是erlang不信任你,担心会产生副作用。

条件语句if:

在erlang中的if和前面说的guards相类似,不同点在于if在函数体内,而guards位于函数头中,可以看看下面的例子:

heh_fine(N) ->
  if N=:=3 -> works
  end,
  if N=:=2 -> works2
  end.

然而我们在运行的时候可以发现,程序却没有运行成功。

** exception error: no true branch found when evaluating an if expression
     in function  hello:heh_fine/1 (hello.erl, line 37)

理由很简单,因为在erlang中,你必须有返回,因此在if中需要有“else”,在erlang中用true表示,因此语法如下:

oh_god(N) ->
    if N =:= 2 -> might_succeed;
    true -> always_does  %% This is Erlang's if's 'else!'
end. 

如果想实现if…elseif…else这样的效果应该怎么实现呢?如下所示即可:

heh_fine(N) ->
  if N=:=3 -> works;
     N=:=2 -> works;
     true -> hello
  end.

if语句中的判断条件也属于Guards,不能有自定义的函数。如果你想要更加灵活,可以使用case of语句,它允许使用自定义函数作为判断条件。

insert(X, []) ->
  [X];
insert(X, Set) ->
  case lists:member(X, Set) of
    true -> Set;
    false -> [X | Set]
  end.

不仅如此,case of 还可以配合Guards一起使用:

beach(Temperature) ->
    case Temperature of
        {celsius, N} when N >= 20, N =< 45 ->
            'favorable';
        {kelvin, N} when N >= 293, N =< 318 ->
            'scientifically favorable';
        {fahrenheit, N} when N >= 68, N =< 113 ->
            'favorable in the US';
        _ ->
            'avoid beach'
  end.

关于条件判断的语句介绍到这儿,下一章节将介绍函数式的精髓部分:递归

发布了42 篇原创文章 · 获赞 9 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/jjxojm/article/details/52571796