文档章节

Erlang if、case、guard和函数

leeyi
 leeyi
发布于 2016/08/10 11:25
字数 1703
阅读 57
收藏 0

Erlang 函数、if、case、guard

每节排版顺序:伪代码,说明文字,案例

函数

伪代码

%单一语句的的函数
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中,函数参数的数量叫做元数。使用箭头(->)来分隔函数头和函数主体。

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表达式的结果是上面这一系列语句的返回值,它就是被执行的分支中最后执行语句的计算值。

案例

     %前面面代码省略 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不是把函数的真实参数和形式参数进行模式匹配,而是通过对一个表达式求值,然后对它的结果和一个由分号隔开的模式匹配列表进行匹配。

使用的关键字是case、of和end。对conditional-expression求值,然后和Pattern1,...,PatternN进行匹配,直到第一个模式匹配成功。->符号把语句的模式或者头部与由逗号分隔的表达式列表组成的主体分开。一旦模式匹配成功,选中的语句表达式就会一个个按次序执行,case结构的结果就是最后一个表达式的运行结果。

与函数定义一样,case表达式的结果必须和一个模式匹配,否则将会得到一个运行时错误。如果在最后的模式中有_或者未绑定变量,那么它将匹配任何Erlang项元,这就如我们在第2章中讨论的catch-all语句一样。catch-all语句不是必需的,事实上,不鼓励把它作为一种防错性编程的形式来使用。

案例

%% 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]).

© 著作权归作者所有

共有 人打赏支持
leeyi
粉丝 5
博文 46
码字总数 52736
作品 0
深圳
后端工程师
私信 提问
加载中

评论(1)

leeyi
leeyi
如果有错别字,或者案例有问题,欢迎留言反馈
[Erlang 0011] Erlang 杂记Ⅱ

学习Erlang的时候在书的留白处随手记录了一些东西,还有一些记录在了demo的注释里面,今天又整理出来了一部分,分享一下. 上一次的地址:[Erlang 0009] Erlang 杂记 Erlang属于面向消息的语言,面...

唐玄奘
2017/12/03
0
0
Swift 2.0 异常处理

Swift 2.0 异常处理 WWDC 2015 宣布了新的 Swift 2.0. 这次重大更新给 Swift 提供了新的异常处理方法。这篇文章会主要围绕这个方面进行讨论。 如何建造异常类型? 在 iOS 开发当中,我们会面...

法斗斗
2016/03/01
6
0
转载:Erlang 函数(Efficiency Guide)

转自:http://www.cnblogs.com/futuredo/archive/2012/10/26/2737644.html Functions 1 Pattern matching 模式匹配 Pattern matching in function head and in case and receive clauses ar......

宁静_夏天
2013/12/12
0
0
[Erlang 0120] Know a little Core Erlang

Erlang开发者或多或少都用过或者听说过Core erlang,它是什么样的呢?新建一个测试模块a.erl,如下操作会生成core erlang代码而非a.beam: 这时文件夹中已经生成了一个a.core的文件,然后我们如下...

唐玄奘
2017/12/08
0
0
c(tuples1). tuples1.erl:20: illegal guard expression

erl 编译之后报错, 我本意是: showPerson/1 函数输出 用户信息,他的参数要么是 元祖 {Name, Age, Phone} 要么是 记录 -record (person, {name, age=0, phone=""}). 求指点,给个争取的实现...

leeyi
2015/10/12
158
1

没有更多内容

加载失败,请刷新页面

加载更多

new Date() 在Safari下的 Invalid Date问题

问题复现 var timeStr = '2018-11-11 00:00:00';var time = new Date(timeStr);// error: Invalid Date... 在safari浏览器下,time为Invalid Date, 导致后面代码执行错误; 其他浏览器诸...

会写代码的husky
14分钟前
1
0
0009-如何升级Cloudera Manager和CDH

1.文档编写目的 本文档讲述如何升级Cloudera Manager和CDH,通过本文档,您将学习到以下知识: 1.如何对Cloudera Manager进行停机升级 2.如何对CDH进行停机升级 3.如何在不影响集群作业的情况...

Hadoop实操
24分钟前
0
0
vue2中引用 better-scroll的方法

文章主要介绍了vue2中引用better-scroll和使用 better-scroll的方法,使用时有三个要点及注意事项在文中给大家详细介绍 ,需要的朋友可以参考下 使用时有三个要点: 一:html部分 <div class...

前端攻城老湿
34分钟前
0
0
浅谈教你如何掌握Linux系统

linux能做什么?相信绝大数人都有这样的疑问。可以玩吃鸡吗?可以玩lol吗? 如果你是以娱乐的名义来评价linux的可用性,对不起,linux可能不适合你,因为linux是一个工具,他是教你聪明的,不...

linuxprobe16
40分钟前
0
0
java中线程池的生命周期

线程池生命周期包括: RUNNING:接收新的任务并处理队列中的任务 SHUTDOWN:不接收新的任务,但是处理队列中的任务 STOP:不接收新的任务,不处理队列中的任务,同时中断处理中的任务 TIDYING:所...

小刀爱编程
48分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部