Los protocolos son:
defprotocol.defimpl.Una gran ventaja de los protocolos es que la implementación de un protocolo para un tipo de datos concreto no tiene que ir incluida junto con la definición de ese tipo de datos ni con la del propio protocolo. Esto permite escribir bibliotecas que sus usuarios pueden ampliar fácilmente para que funcionen con sus propios tipos de datos, sin tener que modificar la biblioteca.
Es posible implementar protocolos para todos los tipos de Elixir: Tuple, Atom, List, BitString, Integer, Float, Function, PID, Map, Port, Reference, Any y los structs.
Los protocolos se pueden implementar para varios tipos a la vez:
defimpl Reversible, for: [Map, List] do
def reverse(term) do
Enum.reverse(term)
end
end
Cuando implementas un protocolo para un struct directamente dentro de un módulo que define ese struct, puedes omitir el argumento :for:
defmodule ShoppingCart do
defstruct [:items]
defimpl Reversible do
def reverse(shopping_cart) do
Enum.reverse(shopping_cart)
end
end
end
Any
De forma predeterminada, invocar un protocolo para un tipo de datos para el que no se ha implementado lanzará un error Protocol.UndefinedError:
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
Es posible evitarlo proporcionando una implementación de reserva que se usaría en ese caso. Para ello, establece el atributo de módulo @fallback_to_any a true al definir el protocolo y escribe una implementación para el tipo Any:
defprotocol Reversible do
@fallback_to_any true
def reverse(term)
end
defimpl Reversible, for: Any do
def reverse(term) do
term
end
end
Ten en cuenta que, en la mayoría de los casos, lanzar un error es lo preferible, porque es difícil hacer una suposición razonable sobre un protocolo para todos los tipos de datos.
Enumerable: las funciones de los módulos Enum y Stream funcionan con los tipos de datos que implementan este protocolo.Collectable: la función Enum.into/2 usa este protocolo para insertar un enumerable en una colección.Inspect: puedes implementar este protocolo para cambiar cómo Kernel.inspect/2 representa un tipo de datos concreto como string.String.Chars: puedes implementar este protocolo para cambiar cómo Kernel.to_string/1 representa un tipo de datos concreto como string.