文档章节

Erlang if、case、guard和函数

leeyi
 leeyi
发布于 2016/08/10 11:25
字数 1703
阅读 47
收藏 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
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
[Erlang 0120] Know a little Core Erlang

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

唐玄奘
2017/12/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

00.编译OpenJDK-8u40的整个过程

前言 历经2天的折腾总算把OpenJDK给编译成功了,要说为啥搞这个,还得从面试说起,最近出去面试经常被问到JVM的相关东西,总感觉自己以前学的太浅薄,所以回来就打算深入学习,目标把《深入理...

凌晨一点
今天
4
0
python: 一些关于元组的碎碎念

初始化元组的时候,尤其是元组里面只有一个元素的时候,会出现一些很蛋疼的情况: def checkContentAndType(obj): print(obj) print(type(obj))if __name__=="__main__": tu...

Oh_really
昨天
6
2
jvm crash分析工具

介绍一款非常好用的jvm crash分析工具,当jvm挂掉时,会产生hs_err_pid.log。里面记录了jvm当时的运行状态以及错误信息,但是内容量比较庞大,不好分析。所以我们要借助工具来帮我们。 Cras...

xpbob
昨天
122
0
Qt编写自定义控件属性设计器

以前做.NET开发中,.NET直接就集成了属性设计器,VS不愧是宇宙第一IDE,你能够想到的都给你封装好了,用起来不要太爽!因为项目需要自从全面转Qt开发已经6年有余,在工业控制领域,有一些应用...

飞扬青云
昨天
4
0
我为什么用GO语言来做区块链?

Go语言现在常常被用来做去中心化系统(decentralised system)。其他类型的公司也都把Go用在产品的核心模块中,并且它在网站开发中也占据了一席之地。 我们在决定做Karachain的时候,考量(b...

HiBlock
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部