Goal
キーワードリストのkeyによって処理を変える一例。
Dev-Environment
OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Text
キーワードリストを使ってarguments的なものをやってみる。
・forで行う簡単な例
defmodule OptionArguments do
def sample(action, opts \\ []) do
for opt <- opts do
case opt do
{:ok, value} -> IO.inspect "ok: #{value}"
{:hoge, value} -> IO.inspect "hoge: #{value}"
{:huge, value} -> IO.inspect "huge: #{value}"
{:foo, value} -> IO.inspect "foo: #{value}"
{:var, value} -> IO.inspect "bar: #{value}"
_ -> IO.inspect "No match!!"
end
end
Map.put_new(%{}, action, opts)
end
end
実行してみる。
iex> OptionArguments.sample :walk, hoge: 1, foo: 2
"hoge: 1"
"foo: 2"
%{walk: [hoge: 1, foo: 2]}
or
iex> OptionArguments.sample(:walk, hoge: 1, foo: 2)
"hoge: 1"
"foo: 2"
%{walk: [hoge: 1, foo: 2]}
どうせなので、望んでいる引数の型を分かりやすくするために、
アノテーションを付けて型情報を明示的にしてみます。
アノテーションを付けて型情報を明示的にしてみます。
defmodule OptionArguments do
@type action :: :walk | :run | :hop | :step | :jump
@spec sample(action, Keyword.t) :: %{action => Keyword.t}
def sample(action, opts \\ []) do
for opt <- opts do
case opt do
{:ok, value} -> IO.inspect "ok: #{value}"
{:hoge, value} -> IO.inspect "hoge: #{value}"
{:huge, value} -> IO.inspect "huge: #{value}"
{:foo, value} -> IO.inspect "foo: #{value}"
{:var, value} -> IO.inspect "bar: #{value}"
_ -> IO.inspect "No match!!"
end
end
Map.put_new(%{}, action, opts)
end
end
実行は同じ結果なので割愛。
Description:
@typeで型情報を自分で作っている。
@specで型情報を使って宣言をしている。
@typeで型情報を自分で作っている。
@specで型情報を使って宣言をしている。
詳しく知りたい方はドキュメントかGetting Startを見て下さい。
hexdocs - v1.0.5 Elixir Kernel.Typespec
elixir-lang - Typespecs and behaviours
hexdocs - v1.0.5 Elixir Kernel.Typespec
elixir-lang - Typespecs and behaviours
Caution:
@specは型を強制するものではありません。
@specは型を強制するものではありません。
実際に適当な値を渡してみて下さい。
特に問題なく実行されます。
特に問題なく実行されます。
iex> OptionArguments.sample :main, hoge: 1, foo: 2
"hoge: 1"
"foo: 2"
%{main: [hoge: 1, foo: 2]}
別段難しい内容ではなかったですね。
といいますか・・・こんな簡単にargs的なのできるんですね。
C++使ってた時は、もっと面倒にやっていた記憶があります(笑)
といいますか・・・こんな簡単にargs的なのできるんですね。
C++使ってた時は、もっと面倒にやっていた記憶があります(笑)
・再帰で行う少し複雑な例
ついでなので、少し複雑な例を一つやりましょう。
たまには頭を使わないといけませんね。(この程度とか言わないで・・・)
たまには頭を使わないといけませんね。(この程度とか言わないで・・・)
defmodule ArgumentsTest do
@spec sample(Keyword.t) :: any
def sample(kw) do
keys = Keyword.keys(kw)
values = Keyword.values(kw)
IO.puts "Start..."
sample(keys, values)
end
@match1 [:hoge, :huge]
@match2 [:foo, :bar]
defp sample([key|keys_tail], [value|values_tail]) when key in @match1 do
IO.puts "@match1 match"
IO.puts "#{key} = #{value}"
sample(keys_tail, values_tail)
end
defp sample([key|keys_tail], [value|values_tail]) when key in @match2 do
IO.puts "@match2 match"
IO.puts "#{key} = #{value}"
sample(keys_tail, values_tail)
end
defp sample(key, value) do
IO.puts "...End"
end
end
Description:
以下の部分ですが・・・キーワードリストのkey部分のみを抽出しています。
以下の部分ですが・・・キーワードリストのkey部分のみを抽出しています。
keys = Keyword.keys(kw)
同じく、キーワードリストのvalue部分のみを抽出しています。
values = Keyword.values(kw)
Example:
iex> Keyword.keys([hoge: 1, foo: 2, bar: 3, hoge: 4, huge: 5])
[:hoge, :foo, :bar, :hoge, :huge]
iex> Keyword.values([hoge: 1, foo: 2, bar: 3, hoge: 4, huge: 5])
[1, 2, 3, 4, 5]
Caution:
:hoge、:huge、:foo、:barにマッチしない場合の処理は書いていません。
現在のままだとマッチしないキーが来たら、そこで処理が終わります。
:hoge、:huge、:foo、:barにマッチしない場合の処理は書いていません。
現在のままだとマッチしないキーが来たら、そこで処理が終わります。
さて、実行してみましょう。
iex> ArgumentsTest.sample hoge: 1, foo: 2, bar: 3, hoge: 4, huge: 5
Start...
@match1 match
hoge = 1
@match2 match
foo = 2
@match2 match
bar = 3
@match1 match
hoge = 4
@match1 match
huge = 5
...End
:ok
順番に実行の流れを見てみましょう。
1:
# sample(kw)を実行
sample([hoge: 1, foo: 2, bar: 3, hoge: 4, huge: 5])
# keysとvaluesの内容
keys: [:hoge, :foo, :bar, :hoge, :huge]
values: [1, 2, 3, 4, 5]
# マッチさせる内容
@match1 [:hoge, :huge]
@match2 [:foo, :bar]
2:
# when key in @match1にマッチ
sample([:hoge|[:foo, :bar, :hoge, :huge]], [1|[2, 3, 4, 5]])
3:
# when key in @match2にマッチ
sample([:foo|[:bar, :hoge, :huge]], [2|[3, 4, 5]])
4:
# when key in @match2にマッチ
sample([:bar|[:hoge, :huge]], [3|[4, 5]])
5:
# when key in @match1にマッチ
sample([:hoge|[:huge]], [4|[5]])
6:
# when key in @match1にマッチ
sample([:huge|[]], [5|[]])
7:
# sample(key, value)にマッチ
sample([], [])
こうすれば、キーによって処理を変えることができる。
Ectoでfromを処理する時にやっていると聞いたので、気になって作ってみた。
Ectoでfromを処理する時にやっていると聞いたので、気になって作ってみた。
書き終わって気付いたのですが、
一例と言っておきながら、二つの例を上げている・・・
一例と言っておきながら、二つの例を上げている・・・