Elixir Language
関数
サーチ…
匿名関数
Elixirでは、一般的な慣行として、匿名関数を使用します。無名関数の作成は簡単です:
iex(1)> my_func = fn x -> x * 2 end
#Function<6.52032458/1 in :erl_eval.expr/5>
一般的な構文は次のとおりです。
fn args -> output end
読みやすくするために、引数の前後にかっこを入れることができます:
iex(2)> my_func = fn (x, y) -> x*y end
#Function<12.52032458/2 in :erl_eval.expr/5>
無名関数を呼び出すには、割り当てられた名前で呼び出して追加し.
名前と引数の間に
iex(3)>my_func.(7, 5)
35
引数なしで匿名関数を宣言することは可能です:
iex(4)> my_func2 = fn -> IO.puts "hello there" end
iex(5)> my_func2.()
hello there
:ok
キャプチャ演算子の使用
匿名関数をより簡潔にするために、 キャプチャ演算子 &
使用することができます。たとえば、次の代わりに:
iex(5)> my_func = fn (x) -> x*x*x end
あなたは書ける:
iex(6)> my_func = &(&1*&1*&1)
複数のパラメータを使用する場合は、各引数に対応する数値を1
から数えて使用します。
iex(7)> my_func = fn (x, y) -> x + y end
iex(8)> my_func = &(&1 + &2) # &1 stands for x and &2 stands for y
iex(9)> my_func.(4, 5)
9
複数の団体
無名関数は、( パターンマッチングの結果として)複数のボディを持つこともできます:
my_func = fn
param1 -> do_this
param2 -> do_that
end
複数のボディを持つ関数を呼び出すときElixirは、提供したパラメータを適切な関数本体と照合しようとします。
関数リストとしてのキーワードリスト
複数のKey-Valueペアを含む 'options'形式のパラメータにキーワードリストを使用する:
def myfunc(arg1, opts \\ []) do
# Function body
end
上記の関数を以下のように呼び出すことができます:
iex> myfunc "hello", pizza: true, soda: false
これは以下と同等です:
iex> myfunc("hello", [pizza: true, soda: false])
引数の値は、それぞれopts.pizza
およびopts.soda
として使用できます。
あるいは、atoms: opts[:pizza]
とopts[:soda]
使用することもできます。
名前付き関数とプライベート関数
名前付き関数
defmodule Math do
# one way
def add(a, b) do
a + b
end
# another way
def subtract(a, b), do: a - b
end
iex> Math.add(2, 3)
5
:ok
iex> Math.subtract(5, 2)
3
:ok
プライベート関数
defmodule Math do
def sum(a, b) do
add(a, b)
end
# Private Function
defp add(a, b) do
a + b
end
end
iex> Math.add(2, 3)
** (UndefinedFunctionError) undefined function Math.add/2
Math.add(3, 4)
iex> Math.sum(2, 3)
5
パターンマッチング
Elixirは、引数の値に基づいて本体の関数呼び出しを照合します。
defmodule Math do def factorial(0): do: 1 def factorial(n): do: n * factorial(n - 1) end
ここで、正数の階乗は第2節と一致し、 factorial(0)
は最初の節と一致します。 (単純化のために負の数を無視する)。 Elixirは上から下に関数をマッチさせようとします。 2番目の関数が1番目の関数の上に書かれている場合、無限の再帰に行くので予期せぬ結果になります。 factorial(0)
はfactorial(n)
一致するので、
ガード句
ガード句を使用すると、関数を実行する前に引数をチェックできます。ガード句は、通常、読みやすさのためにif
とcond
より優先され、コンパイラにとって特定の最適化手法を容易にします。すべてのガードが一致する最初の関数定義が実行されます。
ガードとパターンマッチングを使用した階乗関数の実装例を次に示します。
defmodule Math do def factorial(0), do: 1 def factorial(n) when n > 0: do: n * factorial(n - 1) end
最初のパターンは、引数が0
場合にのみ一致し0
。引数が0
でなければ、パターンの一致は失敗し、次の次の関数がチェックされます。
その2番目の関数定義には、ガード節がありますwhen n > 0
です。つまり、この関数は、引数n
が0
より大きい場合にのみ一致します。結局のところ、数学的階乗関数は負の整数に対して定義されていません。
関数定義(パターンマッチングとガード句を含む)が一致しない場合、 FunctionClauseError
が発生します。これは、負の数が定義されていないため、負の数を引数として渡すときにこの関数で発生します。
このFunctionClauseError
自体は間違いではないことに注意してください。他のいくつかの言語でよく見られるように、 -1
や0
などの「エラー値」を返すと、未定義の関数を呼び出してエラーの原因を隠してしまい、将来の開発者にとって巨大なバグが発生する可能性があります。
デフォルトパラメータ
構文を使用して、任意の名前付き関数にデフォルトのパラメータを渡すことができます: param \\ value
:
defmodule Example do def func(p1, p2 \\ 2) do IO.inspect [p1, p2] end end Example.func("a") # => ["a", 2] Example.func("b", 4) # => ["b", 4]
キャプチャ機能
他のモジュールから関数をキャプチャするには、 &
を使用します。キャプチャされた関数は、関数パラメータとして、または匿名関数内で直接使用できます。
Enum.map(list, fn(x) -> String.capitalize(x) end)
&
を使用してより簡潔にすることができます:
Enum.map(list, &String.capitalize(&1))
引数を渡さずに関数をキャプチャするには、その文字列を明示的に指定する必要があります(例: &String.capitalize/1
:
defmodule Bob do
def say(message, f \\ &String.capitalize/1) do
f.(message)
end
end