cf. 5 case,condそしてif – case, cond and if – Elixir
case
case は1つの値をいずれかの句(clause)にマッチするまで、複数の句と比較する。
iex(1)> case {1, 2, 3} do ...(1)> {4, 5, 6} -> "This clause won't match" ...(1)> {1, x, 3} -> "This clause will match and bind x to 2 in this clause" ...(1)> _ -> "This clause would match any value" ...(1)> end "This clause will match and bind x to 2 in this clause"
上の例では、2番目の句がマッチして、変数 x
に値 2
が束縛されている。この変数 x
は句の中だけで有効らしい。
もし、すでにある変数にマッチさせたい場合は ^ (ピン演算子)を使う。
iex(2)> x = 1 1 iex(3)> case 10 do ...(3)> ^x -> "Won't match" ...(3)> _ -> "Will match" ...(3)> end "Will match"
句にはガード(guard)をつけることで、条件を追加することができる。
iex(4)> case {1, 2, 3} do ...(4)> {1, x, 3} when x > 0 -> "Will match" ...(4)> _ -> "Won't match" ...(4)> end "Will match"
ガードに使える式には制限があるけど、詳しくはリンク先参照。制限といっても普通に使う分には困らない程度に見える。
ガードで起きたエラーは、単にガードの失敗とみなされて外には影響しない。次の例では、hd(x)
の x
がリストではないのでエラーになってるはずだけど、case
全体としてはエラーにならない。
iex(5)> case 1 do ...(5)> x when hd(x) -> "Won't match" ...(5)> x -> "Got: #{x}" ...(5)> end "Got: 1"
もし、どの句にもマッチしなければエラーになる。
iex(6)> case :ok do ...(6)> :error -> "Won't match" ...(6)> end ** (CaseClauseError) no case clause matching: :ok
匿名関数
ちょっと話がそれるけど、匿名関数も句やガードを持つことができる。
iex(6)> f = fn ...(6)> x, y when 0 > x -> x + y ...(6)> x, y -> x * y ...(6)> end #Function<12.52032458/2 in :erl_eval.expr/5> iex(7)> f.(1, 3) 3 iex(8)> f.(-1, 3) 2
cond
Scheme の cond
と同じ。
iex(9)> cond do ...(9)> 2 + 2 == 5 -> "This will not be true" ...(9)> 2 * 2 == 3 -> "Nor this" ...(9)> 1 + 1 == 2 -> "But this will" ...(9)> end "But this will"
もし、true
になる条件がなければエラーになる。
iex(10)> cond do ...(10)> 2 + 2 == 5 -> "This is never true" ...(10)> 2 * 2 == 3 -> "Nor this" ...(10)> end ** (CondClauseError) no cond clause evaluated to a true value
ifとunless
試したい条件が1つだけの時は、if
か unless
マクロが使える。……なんか「マクロ」って単語がさらっと出てきたぞ。
iex(10)> if true do ...(10)> "This works" ...(10)> end "This works" iex(11)> unless true do ...(11)> "This will never be seen" ...(11)> end nil
else
も使える。
iex(12)> if nil do ...(12)> "This won't be seen" ...(12)> else ...(12)> "This will" ...(12)> end "This will"
doブロック
if は次のようにも書ける。
iex(13)> if true, do: 1 + 2 3
Elixir では do ~ end は、式のまとまりを do: へ渡す役割をしている。次の2つの例は同じことをしている。
iex(14)> if true do ...(14)> a = 1 + 2 ...(14)> a + 10 ...(14)> end 13 iex(15)> if true, do: ( ...(15)> a = 1 + 2 ...(15)> a + 10 ...(15)> ) 13
2つ目の構文は「キーワードリストを使っている」と言う。もちろん else も使える。
iex(16)> if false, do: :this, else: :that :that