Tracks
/
Elixir
Elixir
/
Temario
/
Protocolos
Pr

Protocolos en Elixir

4 ejercicios

Acerca de Protocolos

Los protocolos son:

  • Un mecanismo para lograr polimorfismo.
  • Se definen con defprotocol.
  • Se implementan para un tipo de datos concreto con 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.

Implementación

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

Alternativa de reserva con 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.

Protocolos integrados destacables

  • 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.
Editar en GitHub El enlace se abre en una nueva ventana o pestaña

Aprende Protocolos

La práctica está bloqueada

Desbloquea 1 ejercicio más para practicar Protocolos