Los protocolos son:
defprotocol.defimpl.Una gran fortaleza de los protocolos es que la implementación de un protocolo para un tipo de dato específico no necesita venir junto con la definición de ese tipo de dato ni con la definición del protocolo. Esto permite escribir bibliotecas que sus usuarios pueden extender fácilmente para que funcionen con los tipos de datos personalizados de esos usuarios, 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 dato que no lo implementa 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 evitar eso si proporcionas una implementación de respaldo que se use en un caso así. Para hacerlo, asigna true al atributo de módulo @fallback_to_any cuando definas 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 lo preferible es lanzar un error, 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 dentro de una colección.Inspect: puedes implementar este protocolo para cambiar la forma en que Kernel.inspect/2 representa un tipo de dato específico como un string.String.Chars: puedes implementar este protocolo para cambiar la forma en que Kernel.to_string/1 representa un tipo de dato específico como un string.