函数式语言常使用模式匹配来做控制结构,但这并不意味着Elixir就没有通常的if-else
结构。在Elixir中,if 却不是语句而是宏。这一点在理解宏之前,暂时把他看出语句表达式吧。一般语句没有返回值,表达式有返回值,elixir中if宏是有返回值的。就像字典结构一样,elixir提供了好几个这样的结构,对于经典的条件结构,elixir同样也提供了 if
unless
cond
和 case
好几种方式。
if 宏
if宏比较简单,和别的编程语言差别不到,其基本语法如下:
if condition do
...
else
...
end
条件(condition)表达式求值为ture,则执行其下面的代码,否则执行else里的代码。当然,如果具体执行的逻辑代码是一行,则有如下的简写成一行
if condition, do: somthing, else: anther_ting
。
可以通过 h 查看 if的用法
iex(1)> h if
defmacro if(condition, clauses)
Provides an if macro. This macro expects the first argument to be a condition
and the rest are keyword arguments.
One-liner examples
┃ if(foo, do: bar)
In the example above, bar will be returned if foo evaluates to true (i.e. it is
neither false nor nil). Otherwise, nil will be returned.
An else option can be given to specify the opposite:
┃ if(foo, do: bar, else: baz)
Blocks examples
Elixir also allows you to pass a block to the if macro. The first example above
would be translated to:
┃ if foo do
┃ bar
┃ end
Notice that do/end becomes delimiters. The second example would then translate
to:
┃ if foo do
┃ bar
┃ else
┃ baz
┃ end
If you want to compare more than two clauses, you can use the cond/1 macro.
iex(2)>
if 本质上是一个宏,这个宏接受参数,第一个参数是 condition
,第二个参数可以是一个keyword [do: bar]
, 只不过[]
可以省略,就写成了 do: bar
,keyword列表还可以提供else部分。执行do还是else的逻辑,取决于 condition的求值。if宏的返回值为do或者else执行后的返回值。在尚未了解宏之前,可以把 do else
展成代码块(元编程的精髓)。
iex(2)> if 5 > 0, do: :true
true
iex(3)> if 5 < 0, do: :true
nil
iex(4)> if 5 < 0, do: :true, else: :false
false
iex(5)> if 5 < 0, [do: :true, else: :false]
false
iex(6)> if(5 < 0, [do: :true, else: :false])
false
iex(7)> if(5 < 0, [{:do, :true}, {:else, :false}])
false
iex(8)> if 5 > 0 do
...(8)> :ture
...(8)> else
...(8)> :false
...(8)> end
:ture
cond
经典的条件控制往往还有if elif else这样的多路条件。elixir也有类似的,即cond宏。cond做条件Lisp用得很频繁。cond没有简写模式,其基本形式为:
cond do
expression_1 ->
...
expression_2 ->
...
...
end
如果没有条件符合,最后会报错,所以通常的做法是写一个default的语句:
iex(1)> cond do
...(1)> 1 + 1 == 1 ->
...(1)> "This will never match"
...(1)> 2 * 2 !=4 ->
...(1)> "Nor this"
...(1)> true ->
...(1)> "This will"
...(1)> end
"This will"
case
cond语句在Lisp中大行其道,elixir更多喜好模式匹配,因此还有case宏可以做多路条件判断。case的语法也很简单:
case expression do
pattern_1 ->
...
pattern_2 ->
...
...
end
case使用expression表达式做为模式匹配的右边,模式匹配成功则执行其代码块内容,并返回代码块中的返回值。无法匹配的,同样也会抛出异常, 比正常的模式匹配更高级的一点在于,case的模式可以接受when这样的gurads语句。
iex(3)> case {:ok, "hello"} do
...(3)> {:ok, value} when is_number(value) ->
...(3)> value
...(3)> {:ok, value} ->
...(3)> "OK"
...(3)> true ->
...(3)> "always true"
...(3)> end
"OK"
以上就是elixir中的条件控制结构,相对而言,还是比较简单的,和其他语言经典的条件控制非常相似。尽管宏定义的时候,其简写方法有点怪。可是宏不就是为了展开进行元编程嘛。实质上这些宏展开了都是标准的条件判断写法,可见宏编程的强大。
除了条件控制结构,常用的控制结构就是循环。不同于别的语言,elixir并没有提供直接用于循环的while,for等循环结构,取而代之的是通过函数的递归来实现循环迭代的需求。下一节将会介绍循环的做法---递归和迭代。