1. OverView
だんだん、チートシート書いてんだか、解説してんだか、Elixir Schoolの無断転載してんのかわからなくなってきましたw
2 まずは解説
2.1 プライベート関数
他のモジュールから特定の関数へアクセスさせたくない時には関数をプライベートにすることができます。
お説教はおいておくと、「他人に使われたくない関数」と言うのは結構ありまして、そう言う時に使うもんだとご理解ください。
さて、サンプル
defmodule Greeter do
def hello(name), do: phrase() <> name
defp phrase, do: "Hello, "
end
defで定義されている関数 pharase/0が、プライベート関数です。
実行してみましょう、hello/1は実行出来ても、phrase/0が実行できていないのがわかります。
iex(36)> Greeter.hello("Sean")
"Hello, Sean"
iex(37)> Greeter.phrase
** (UndefinedFunctionError) function Greeter.phrase/0 is undefined or private
Greeter.phrase()
iex:37: (file)
iex(37)>
…をを!シンプルに説明が終わったぞ!…丸写しだもんな。
2.2 ガード節
ガード節は、関数のパターンマッチングにおいて、「追加の条件を指定するために使用されます」。
ガード節を使うことで、関数の引数が特定の条件を満たす場合にのみ、その関数が実行されるように制御できます。
when句を指定し、「追加の条件」を追加しております。
では、サンプルを見てみましょう
defmodule Greeter do
def hello(names) when is_list(names) do
names = Enum.join(names, ", ")
hello(names)
end
def hello(name) when is_binary(name) do
phrase() <> name
end
defp phrase, do: "Hello, "
end
さて、実行してみましょう。
iex(2)> Greeter.hello ["Sean", "Steve"]
"Hello, Sean, Steve"
iex(3)> "Hello, Sean, Steve"
"Hello, Sean, Steve"
iex(4)>
ちゃんとwhen句が動き、どちらも同じhello/1にも関わらず、def hello(names) when is_list(names)とっても再帰が簡単ですね
def hello(name) when is_binary(name) で定義された関数が、呼び分けられてますね。
では、昨日のサンプルを「改良」してみましょう。
defmodule Greeter1 do
def hello(%{name: person_name}) do
IO.puts "Hello, " <> person_name
end
def hello(%{age: person_age}) do
IO.puts "Hello, " <> person_age <> " aged person!"
end
end
こいつに、when句で条件を指定してみましょう。
def hello(%{name: person_name}) do -> こちらは、引数のkeyにname:があった場合に
def hello(%{age: person_age}) do -> こちらは、引数のkeyにname:がなかった場合に
defmodule Greeter1 do
def hello(%{name: person_name} = target) when is_map_key(target, :name) do
IO.puts "Hello, " <> person_name
end
def hello(%{age: person_age} = target) when not is_map_key(target, :name) do
IO.puts "Hello, " <> Integer.to_string(person_age) <> " aged person!"
end
end
これがテストデータです。
fred = %{
name: "Fred",
age: "95",
favorite_color: "Taupe"
}
実行結果。
見事に、使い分けられております。
iex(3)> Greeter1.hello(fred)
Hello, Fred
:ok
iex(4)> Greeter1.hello(%{age: 95, favorite_color: "Taupe"})
Hello, 95 aged person!
:ok
2.3 デフォルト引数
引数にデフォルトが設定出来ます。
引数 \ デフォルト値の記法を用います。
うん、用いてくれるそうです。
defmodule Greeter do
def hello(name, language_code \\ "en") do
phrase(language_code) <> name
end
defp phrase("en"), do: "Hello, "
defp phrase("es"), do: "Hola, "
end
実行してみましょう。
iex(10)> Greeter.hello("Sean", "en")
"Hello, Sean"
iex(11)> Greeter.hello("Sean")
"Hello, Sean"
iex(12)> Greeter.hello("Sean", "es")
"Hola, Sean"
初期値が見事設定されてますねぇ。
なので、hello/1としてもマッチしております。
2.3 デフォルト引数の続き
さて、Elixir Schoolで、「ガードの例をデフォルト引数と組み合わせると、問題にぶつかります。 どんな風になるか見てみましょう」
と問題にぶつかっております。
defmodule Greeter do
def hello(names, language_code \\ "en") when is_list(names) do
names = Enum.join(names, ", ")
hello(names, language_code)
end
def hello(name, language_code \\ "en") when is_binary(name) do
phrase(language_code) <> name
end
defp phrase("en"), do: "Hello, "
defp phrase("es"), do: "Hola, "
end
エラーはこちら
warning: redefining module Greeter (current version defined in memory)
iex:16: Greeter (module)
error: def hello/2 defines defaults multiple times. Elixir allows defaults to be declared once per definition. Instead of:
def foo(:first_clause, b \\ :default) do ... end
def foo(:second_clause, b \\ :default) do ... end
one should write:
def foo(a, b \\ :default)
def foo(:first_clause, b) do ... end
def foo(:second_clause, b) do ... end
iex:23
** (CompileError) cannot compile code (errors have been logged)
def hello/2 defines defaults multiple times. Elixir allows defaults to be declared once per definition.
hello/2にといて、defaultsを複数定義しているElixirは一回しか定義しちゃだめよ、だそうです。
作例まで書いてくれてますね。すっげー便利。修正してみましょう。
「これに対処するには、デフォルト引数付きの関数を先頭に追加します」
defmodule Greeter do
def hello(names, language_code \\ "en")
def hello(names, language_code) when is_list(names) do
names = Enum.join(names, ", ")
hello(names, language_code)
end
def hello(name, language_code) when is_binary(name) do
phrase(language_code) <> name
end
defp phrase("en"), do: "Hello, "
defp phrase("es"), do: "Hola, "
end
実行してみましょう。
iex(18)> Greeter.hello ["Sean", "Steve"]
"Hello, Sean, Steve"
iex(19)> Greeter.hello ["Sean", "Steve"], "es"
"Hola, Sean, Steve"
めでたしめでたし?
3. 本日のチートシート
関数について注意事項 | 説明 | 例 |
---|---|---|
プライベート関数 | 他のモジュールから特定の関数へアクセスさせたくない時には関数をプライベートに出来る | defmodule Greeter do defp phrase, do: "Hello, " end iex(37)> Greeter.phrase エラーとなる |
ガード節 | ガード節は、関数のパターンマッチングにおいて、追加の条件を指定するために使用されます | defmodule Greeter1 do def hello(%{name: person_name} = target) when is_map_key(target, :name) do IO.puts "Hello, " <> person_name end def hello(%{age: person_age} = target) when not is_map_key(target, :name) do IO.puts "Hello, " <> Integer.to_string(person_age) <> " aged person!" end end |
デフォルト引数 | 引数にデフォルトが設定出来ます。引数 \ デフォルト値で指定します |