LoginSignup
1

More than 5 years have passed since last update.

Elixir Protocols

Posted at

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'}

参照

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1