本稿はElixir公式サイトの許諾を得て「case, cond, and if」の解説にもとづき、加筆補正を加えてElixirの条件に応じた処理についてご説明します。
case
case/2はend
で閉じ、その中に条件に応じた処理をいくつでも書き加えられます。条件に合うかどうか決めるのは、パターンマッチングです。残るすべての場合を引き受けるには_
を用います。
iex> case {:ok, "hello world"} do
...> {:ok, result} -> result
...> {:error, error} -> error
...> _ -> "others"
...> end
"hello world"
条件にマッチする処理が書かれていないとエラーになります。
iex> case rem(1, 2) do
...> 0 -> :even
...> end
** (CaseClauseError) no case clause matching: 1
iex> case rem(1, 2) do
...> 0 -> :even
...> 1 -> :odd
...> _ -> :oddity
...> end
:odd
case/2
の外の変数をパターンとして参照するときは、^/1
演算子を添えなければなりません。中で定められる変数とは別の扱いになるからです。
iex> x = 1
1
iex> case 2 do
...> ^x -> 1
...> x -> x
...> end
2
iex> x
1
処理の中にさらにwhen
キーワードで条件(ガード)を加えることができます(「Guards」参照)。
iex> case 3 do
...> 1 -> :one
...> 2 -> :two
...> n when is_integer(n) and n > 2 -> :larger_than_two
...> _ -> :not_integer
...> end
:larger_than_two
無名関数の引数についても、ガードを定めて処理を場合分けできます。
iex> is_even? = fn
...> n when rem(n, 2) == 0 -> true
...> n when rem(n, 2) == 1 -> false
...> _ -> :not_integer
...> end
#Function<6.99386804/1 in :erl_eval.expr/5>
iex> is_even?.(1)
false
iex> is_even?.(2)
true
iex> is_even?.(2.0)
:not_integer
rem/2
関数の引数は整数でなければなりません。けれど、上のコードでガードの式はエラーを出さず、ただパターンにマッチしないと扱われていることにご注意ください。
iex> rem(2.0, 2)
** (ArithmeticError) bad argument in arithmetic expression
:erlang.rem(2.0, 2)
なお、無名関数の処理を引数によって場合分けしたとき、アリティは同じでなければなりません。
iex> case func = fn
...> x -> x
...> x, y -> x + y
...> end
** (CompileError) iex:14: undefined function case/1
cond
case/2
はひとつの値をいくつかのパターンからマッチさせて処理するのに適しています。けれども、条件がさまざまな場合もあるでしょう。そのときに用いるのがcond/1
です。条件は論理値として評価されます。false
とnil
以外はtrue
です。はじめにtrue
と評価された処理が行われます。
iex> cond do
...> 1 > 2 -> false
...> is_integer(1.0) -> false
...> nil -> false
...> [1, 2, 3] -> true
...> true -> "実行されない"
...> end
true
true
と評価される条件がないとエラーになります。そこで、最後に条件がtrue
の処理を加えておくとよいでしょう。
iex> cond do
...> 1 == 2 -> false
...> end
** (CondClauseError) no cond clause evaluated to a true value
ifとunless
評価する条件がひとつだけのときは、if/2
とunless/2
が使えます。これらは言語そのものに備わる機能ではありません。Elixirのマクロとして定められています。
iex> if true do
...> "実行される"
...> end
"実行される"
条件がtrue
と評価されない場合(false
)の処理はelse
ブロックで加えられます。
iex> if !0 do
...> true
...> else
...> false
...> end
false
unless/2
はif/2
と反対に、条件がfalse
と評価されるときに処理を行います。
iex> unless 0 do
...> "実行されない"
...> end
nil
do/endブロック
ご紹介した4つの条件構文case/2
、cond/1
、if/2
、unless/2
は、いずれも処理をdo
/end
ブロックに書きました。このブロックを使わずにひとつの式で書くこともできます。たとえば、if/2
の場合です。
iex> if(0 < 1, do: 1 + 2)
3
iex> if(false, do: :this, else: :that)
:that
if/2
のアリティは2でした。あとの例は引数を3つとっているように見えます。Elixirはdo
とelse
は、それぞれをキーワードとしたひとつのリストと捉えているのです。
iex> if(false, [do: :this, else: :that])
:that
複数の処理は改行で区切ります。
iex(28)> if(true, do: (
...(28)> x = 2
...(28)> x * x
...(28)> ))
4
引数のカンマ区切りとキーワードリストの書き方では、コードが長くなったとき見にくくなります。そこで、do/end
ブロックが採り入れられたのです。
iex> if true do
...> x = 2
...> x * x
...> end
4
条件構文はひとつの式ですから、関数の引数に渡すこともできます。けれども、つぎのコードではエラーになります。これは、構文全体でなく、if
とtrue
のふたつがis_number/1
関数の引数と捉えられてしまったからです。
iex> is_number if true do
...> x = 2
...> end
** (CompileError) iex:32: undefined function is_number/2
構文全体を()
でかこんで、関数のひとつの引数であることをはっきりさせれば正しく動きます。
iex> is_number(
...> if true do
...> x = 2
...> end
...> )
true
Elixir入門もくじ
- Elixir入門 01: コードを書いて試してみる
- Elixir入門 02: 型の基本
- Elixir入門 03: 演算子の基本
- Elixir入門 04: パターンマッチング
- Elixir入門 05: 条件 - case/cond/if
- Elixir入門 06: バイナリと文字列および文字リスト
- Elixir入門 07: キーワードリストとマップ
- Elixir入門 08: モジュールと関数
- Elixir入門 09: 再帰
- Elixir入門 10: EnumとStream
- Elixir入門 11: プロセス
- Elixir入門 12: 入出力とファイルシステム
- Elixir入門 13: aliasとrequireおよびimport
- Elixir入門 14: モジュールの属性
- Elixir入門 15: 構造体
- Elixir入門 16: プロトコル
- Elixir入門 17: 内包表記
- Elixir入門 18: シギル
- Elixir入門 19: tryとcatchおよびrescue
- Elixir入門 20: 型の仕様とビヘイビア
- Elixir入門 21: デバッグ
- Elixir入門 22: Erlangライブラリ
- Elixir入門 23: つぎのステップ
Top comments (0)