Open6
[Elixir] 引数によるパターンマッチ
Elixiriでの引数によるパターンマッチのパターンがいろいろあるので遭遇したものをまとめておく
引数でのstructにてパターンマッチしつつ、値とのパターンマッチ
defmodule A do
def f1(%{a: a = "1st"}), do: IO.puts("this is 1st / " <> a)
def f1(%{a: a}), do: IO.puts("this is 2nd / " <> a)
def f1(_), do: raise("Cannot catch")
end
# iex ----
iex> A.f1(%{a: "1st"})
this is 1st / 1st
iex> A.f1(%{a: "2nd :D"})
this is 2nd / 2nd :D
iex> A.f1(%{a_x: "3rd :/"})
** (RuntimeError) Cannot catch
- Reduxみたいなtype によって処理を変えたいときに使えそう
defmodule A do
def f2(%{a: "1st" = a}), do: IO.puts(a)
def f2(%{a: a = "2nd"}), do: IO.puts(a)
end
# iex ---
iex> A.f2 %{a: "1st"}
1st
iex> A.f2 %{a: "2nd"}
2nd
- 引数にて変数への束縛をする場合は、左右のどちらに置いても変わらない
defmodule D do
use TypedStruct
typedstruct do
field :name, String.t(), enforce: true
field :age, integer()
end
end
defmodule X do
def f1(d = %D{age: age}) do
IO.inspect(d)
end
end
# iex ---
iex> X.f1 %D{name: "name"}
%D{age: nil, name: "name"}
%D{}
はoptionalな要素としてD.age
を持ち、引数に%D{age: age}
を取ったときの挙動
- ageにはnilが入る。構造体的にパターンマッチされないかと思ってた。
- そのため、データ構造の厳格性という観点でパターンマッチはできない
- structのレベルで
enforce: true
にするかvalidatorでチェックしないといけない
iex> d1 = %{name: "NAME", age: 9}
%{age: 9, name: "NAME"}
iex> d2 = %D{name: "NAME", age: 9}
%D{age: 9, name: "NAME"}
iex> d3 = %D{name: "NAME", age: 9}
%D{age: 9, name: "NAME"}
iex> d1 == d2
false
iex> d2 == d3
true
# 無理くりstructを生成
iex> d4 = %{name: "NAME", age: 9, __struct__: D}
%D{age: 9, name: "NAME"}
iex> d4 == d2
true
前提として、名前付き構造体と無名構造体ではパターンマッチしない。
defmodule D do
use TypedStruct
typedstruct do
field :name, String.t(), enforce: true
field :age, integer()
end
end
defmodule C do
def fd2(param = %D{}), do: IO.puts("OK")
end
# iex ---
iex> C.fd2 %D{name: "NAME", age: 9}
OK
iex> C.fd2 %{name: "NAME", age: 9}
** (FunctionClauseError) no function clause matching in C.fd2/1
そのため、引数のパターンマッチにてdefining structとundefinining struct はパターンマッチはしない