Elixir Protocols
概要
Elixir の Protocols について。
Protocols は Elixir のポリモーフィズムの手段です。
Protocol の作成は defprotocol
Protocol の実装は defimpl
で行います。
お題
Elixir では nil と false だけが falsy です。
真偽の判定において、要素が空かどうかは頻出かつ重要です。
サンプルコード
defmodule Person do
defstruct name: 'unknown', age: 0
end
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
defimpl Blank, for: Integer do
def blank?(_), do: false
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defimpl Blank, for: Map do
def blank?(map), do: map_size(map) == 0
end
defimpl Blank, for: Person do
def blank?(%Person{name: 'unknown', age: 0}), do: true
def blank?(_), do: false
end
defmodule Hoge do
require Person
def hoge do
default_person = %Person{}
tanaka = %Person{name: 'tanaka', age: 24}
IO.inspect Blank.blank?(%{})
IO.inspect Blank.blank?(default_person)
IO.inspect Blank.blank?(tanaka)
end
end
IO.inspect Blank.blank?(0)
IO.inspect Blank.blank?(1)
IO.inspect Blank.blank?([])
IO.inspect Blank.blank?([1])
Hoge.hoge
出力
false
false
true
false
true
true
false
組み込み protocols
Enumerable を利用してみます
http://elixir-lang.org/docs/stable/elixir/Enumerable.html
サンプルコード
defmodule Person do
defstruct name: 'unknown', age: 0
end
defmodule People do
require Person
defstruct people: [%Person{}]
end
defimpl Enumerable, for: People do
def count(collection) do
Enum.count(collection.people)
end
def member?(collection, value) do
Enum.member?(collection.people, value)
end
def reduce(collection, acc, fun) do
Enum.reduce(collection.people, acc, fun)
end
end
defmodule Hoge do
require Person
require People
require List
def hoge do
default_person = %Person{}
tanaka = %Person{name: 'tanaka', age: 24}
sato = %Person{name: 'sato', age: 23}
suzuki = %Person{name: 'suzuki', age: 33}
people = %People{people: [default_person, tanaka, sato]}
IO.inspect Enumerable.count(people)
IO.inspect Enumerable.member?(people, sato)
IO.inspect Enumerable.member?(people, suzuki)
IO.inspect Enumerable.reduce(people, 0, fn(x, acc) -> x.age + acc end )
Enum.each people, &IO.inspect(&1)
end
end
Hoge.hoge
出力
3
true
false
47
%Person{age: 0, name: 'unknown'}
%Person{age: 24, name: 'tanaka'}
%Person{age: 23, name: 'sato'}