函數式語言常使用模式匹配來做控制結構,但這并不意味著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等循環結構,取而代之的是通過函數的遞歸來實現循環迭代的需求。下一節將會介紹循環的做法---遞歸和迭代。