在本章,我们将学习 case,cond 和 if 这几个控制流结构。
case
case允许我们将一个值和许多模式进行比较直到我们找到一个匹配的:
|
|
如果你想模式匹配已经存在的变量,你需要使用 ^ 运算符:
|
|
分支语句也允许用卫语句来指定额外的条件:
|
|
上例中第一个分支语句仅在x大于零的时候才被匹配上。
卫语句里的表达式
Elixir默认导入和允许下述表达式在卫语句里:
- 比较运算符(==,!=,===,!==,>, >=, <, <=)
- 布尔运算符(and,or,not)
- 算术运算符(+, -, *, /)
- 一元算术运算符(+, -)
- 二进制数据串联运算符 <>
- in 运算符,只要它右边是一个范围或者一个列表
所有下述类型检查函数:
* is_atom/1 * is_binary/1 * is_bitstring/1 * is_boolean/1 * is_float/1 * is_function/1 * is_function/2 * is_integer/1 * is_list/1 * is_map/1 * is_nil/1 * is_number/1 * is_pid/1 * is_port/1 * is_reference/1 * is_tuple/1
加上下面的函数
* abs(number) * binary_part(binary, start, length) * bit_size(bitstring) * byte_size(bitstring) * div(integer, integer) * elem(tuple, n) * hd(list) * length(list) * map_size(map) * node() * node(pid | ref | port) * rem(integer, integer) * round(number) * self() * tl(list) * trunc(number) * tuple_size(tuple)
另外,用户可以定义他们自己的卫语句。例如,Bitwise模块定义作为函数和运算符的卫语句:bnot,~~~,band,&&&,bor,|||,bxor,^^^,bsl,<<<,bsr,>>>。
注意,虽然布尔运算符,比如:and,or 和 not 运行在卫语句里使用,但是更加通用的运算符 &&,|| 和 ! 却不被允许在卫语句里使用。
切记:卫语句里的错误不会被抛出,而是使得卫语句失败:
|
|
如果没有一个分支匹配,则有错误抛出:
|
|
注意:匿名函数也可以有多个分支和卫语句:
|
|
匿名函数每个分支的入参格式必须相同,否则有错误抛出:
|
|
cond
当你要匹配不同的值的时候,case语句有用。然而,在许多情况中,我们想要检查不同的条件并且找到第一个为true的条件。在这样的场景下,可以使用cond:
|
|
这和许多命令式语言里的 else if 分支等效(虽然不常在这里使用的方法)。
如果没有一个条件返回true,则一个错误(CondClauseError)被抛出。因为这个原因,增加一个最后条件,它等于true,这个条件将总是可以匹配到,这样的做法可能是必要的。
|
|
最后,要注意:cond认为除nil和false外,任何值都是true:
|
|
if 和 unless
除了case和cond,Elixir也提供宏:if/2 和 unless/2 ,它们在你需要仅仅检查一个条件的时候很有用:
|
|
如果给予if/2的条件返回false或nil,则do/end之间的语句不会被执行,并且if/2的整体返回值是nil。unless/2的情况则相反。
它们也支持else块:
|
|
注意:一个关于if/2和unless/2的有趣的注意事项是在Elixir里它们被实现为宏;它们不像在其他语言那样是一个特殊的语言结构。你可以参阅官方文档和Kernel模块的文档中if/2的说明。Kernel模块里也定义了像+/2这样的运算符和像is_function/2这样的函数,这些函数都默认地被自动导入并在你的代码中可用。
do/end块
到此,我们已经学了四种控制结构:case、cond、if 和 unless ,它们都包裹在 do/end 块里。我们也可以像下面这样写 if 控制结构:
|
|
注意上面的例子在 true 和 do: 之间有一个逗号,这是因为它使用了Elixir的正规语法,每个参数用逗号分割。我们说这个语法是用关键字列表。我们也可以传递 else 使用关键字:
|
|
do/end是构建于关键字上的语法便利措施。这就是为什么在前面的参数和语句块之间不需要逗号。它的确非常有用,因为当写代码块的时候它删除了冗余。下面的例子是等效的:
|
|
有一件事要记住,当你使用do/end的时候,它们总是和最外层函数调用绑定的。例如,下面的表达式:
|
|
将被解析为:
|
|
这将导致一个未定义函数错误,因为这个调用传递两个参数,而 is_number/2 并不存在。if true 表达式在这里是无效的,因为它需要代码块;而因为 is_number/2 的参数个数不匹配,Elixir根本就没有调用到它。
增加明确的括号就足以绑定代码块到 if :
|
|
关键字列表Elixir里扮演很重要的角色,并且在许多函数和宏里普遍存在。在后续的章节里我们将进一步探索它们。接下来,我们讨论“二进制、字符串和字符列表”。
原文链接: http://elixir-lang.org/getting-started/case-cond-and-if.html