Trilhas
/
Elixir
Elixir
/
Programa
/
Protocolos
Pr

Protocolos em Elixir

4 exercícios

Sobre Protocolos

Protocolos são:

  • Um mecanismo para alcançar polimorfismo.
  • Definidos com defprotocol.
  • Implementados para um tipo de dados específico com defimpl.

Uma grande vantagem dos protocolos é que a implementação de um protocolo para um tipo de dados específico não precisa vir junto com a definição do tipo de dados nem com a definição do protocolo. Isso permite escrever bibliotecas que os usuários podem estender facilmente para funcionar com seus próprios tipos de dados, sem precisar modificar a biblioteca.

Implementando

É possível implementar protocolos para todos os tipos do Elixir: Tuple, Atom, List, BitString, Integer, Float, Function, PID, Map, Port, Reference, Any, e structs.

Os protocolos podem ser implementados para vários tipos de uma só vez:

defimpl Reversible, for: [Map, List] do
  def reverse(term) do
    Enum.reverse(term)
  end
end

Ao implementar um protocolo para uma struct diretamente dentro de um módulo que define a struct, o argumento :for pode ser omitido:

defmodule ShoppingCart do
  defstruct [:items]

  defimpl Reversible do
    def reverse(shopping_cart) do
      Enum.reverse(shopping_cart)
    end
  end
end

Fallback para Any

Por padrão, invocar um protocolo para um tipo de dados para o qual ele não foi implementado vai levantar um erro 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

É possível evitar isso fornecendo uma implementação de fallback, que seria usada nesse caso. Para fazer isso, defina o atributo de módulo @fallback_to_any como true ao definir o protocolo e escreva uma implementação para o 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

Repare que, na maioria dos casos, levantar um erro é a abordagem preferível, porque é difícil fazer uma suposição razoável sobre um protocolo para todos os tipos de dados.

Protocolos embutidos que merecem atenção

  • Enumerable - as funções dos módulos Enum e Stream funcionam com tipos de dados que implementam esse protocolo.
  • Collectable - a função Enum.into/2 usa esse protocolo para inserir um enumerable em uma coleção.
  • Inspect - você pode implementar esse protocolo para mudar como Kernel.inspect/2 representa um tipo de dados específico como uma string.
  • String.Chars - você pode implementar esse protocolo para mudar como Kernel.to_string/1 representa um tipo de dados específico como uma string.
Editar via GitHub O link abre em uma nova janela ou aba

Aprenda Protocolos

A prática está bloqueada

Desbloqueie mais 1 exercício para praticar Protocolos