A protokollok:
defprotocol segítségével definiáljuk őket.defimpl segítségével implementáljuk őket.A protokollok nagy előnye, hogy egy protokoll adott adattípusra vonatkozó implementációját nem kell sem az adattípus, sem a protokoll definíciójával együtt szállítani. Így olyan könyvtárakat írhatunk, amelyeket a felhasználók könnyedén kiterjeszthetnek a saját egyedi adattípusaikra anélkül, hogy módosítaniuk kellene a könyvtárat.
A protokollokat az összes Elixir-típushoz implementálhatjuk: Tuple, Atom, List, BitString, Integer, Float, Function, PID, Map, Port, Reference, Any és structok.
Egy protokoll egyszerre több típushoz is implementálható:
defimpl Reversible, for: [Map, List] do
def reverse(term) do
Enum.reverse(term)
end
end
Ha egy struct protokollját közvetlenül a structot definiáló modulon belül implementáljuk, a :for argumentum elhagyható:
defmodule ShoppingCart do
defstruct [:items]
defimpl Reversible do
def reverse(shopping_cart) do
Enum.reverse(shopping_cart)
end
end
end
Any típusraAlapértelmezés szerint, ha egy protokollt olyan adattípusra hívunk meg, amelyhez nem implementáltuk, Protocol.UndefinedError hibát kapunk:
to_string({})
# => ** (Protocol.UndefinedError) protocol String.Chars not implemented for {} of type Tuple
# (elixir 1.10.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
# (elixir 1.10.3) lib/string/chars.ex:22: String.Chars.to_string/1
Ezt elkerülhetjük egy tartalék implementációval, amely ilyen esetben lép életbe. Ehhez a protokoll definiálásakor állítsd a @fallback_to_any modulattribútumot true-ra, és írj implementációt az Any típushoz:
defprotocol Reversible do
@fallback_to_any true
def reverse(term)
end
defimpl Reversible, for: Any do
def reverse(term) do
term
end
end
Vedd figyelembe, hogy a legtöbb esetben jobb, ha hibát dobunk, mert nehéz észszerű feltevéssel élni egy protokollról az összes adattípus esetében.
Enumerable - az Enum és Stream modul függvényei olyan adattípusokkal működnek, amelyek implementálják ezt a protokollt.Collectable - az Enum.into/2 függvény ezt a protokollt használja, hogy egy enumerable-t beillesszen egy gyűjteménybe.Inspect - ezt a protokollt implementálva megváltoztathatod, hogyan jeleníti meg a Kernel.inspect/2 egy adott adattípust stringként.String.Chars - ezt a protokollt implementálva megváltoztathatod, hogyan jeleníti meg a Kernel.to_string/1 egy adott adattípust stringként.