Protocolos com Elixir

Os protocolos são uma forma de alcançar polimorfismo utilizando Elixir. Podemos determinar ações para uma função genérica baseado no tipo de dado inserido.

Digamos que você precisa implementar uma função que será responsável por recuperar o primeiro elemento de uma lista.

Teríamos algo mais ou menos assim:

defmodule MyList do
  def first_item([item | _list]), do: item
end


IEx의 예를 사용하여 다음 기능을 시각화할 수 있습니다.

iex> my_list = [1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
iex> MyList.first_item(my_list)
1


Uma vez que criamos este moduloMyList e definimos a função para receber uma lista como paraâmetro através de pattern matching, a sua implementação fica limitada a somente listas não-vazias.

O uso de outro tipo de dado como argumento geraria o seguinte erro:

iex> MyList.first_item(%{t: 2, b: 3})
** (FunctionClauseError) no function clause matching in MyList.first_item/1


Podemos resolver esse problema de duas maneiras, onde uma delas seria implementar uma nova função com um guard que cumpra os requisitos para Maps:

defmodule MyList do
  def first_item([item | _list]), do: item
  def first_item(map) when is_map(map) do
    map
    |> Enum.to_list()
    |> List.first()
  end
end


E dessa forma seria possível utilizar maps e listas como argumentos, 예:

iex> list = [1,2,3,4,5,6,7,8,9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
iex> map = %{a: 1, b: 2}
%{a: 1, b: 2}
iex> MyList.first_item(list)
1
iex> MyList.first_item(map)
{:a, 1}


Enquanto isso, a segunda opção para resolver este problema seria implementar um protocolo para essa função e garantir que esse protocolo funcione para as seguintes implementações: [Lista, Map]

Mas como fazemos isso?



프로토콜 및 구현



Fazendo uma breve analogia a linguagens OO (Orientada a Objetos), podemos ver o Protocolo em si como uma Interface, onde iremos definir a assinatura de um método, e as implementações como o famoso @override que usamos para dizer que queremos sobrescrever a implementação de estamos 구현에 대한 인터페이스의 기능을 결정합니다.

A definição de protocolos é feita através da estruturadefprotocol , 다음 형식:

defprotocol MyList do
  def first_item(value)
end


Não precisamos dizer como a função first_item/1 irá funcionar, basta indicar que estamos criando esse protocolo e que ele precisa possuir as devidas implementações para funcionar de acordo com o esperado.

Agora vamos fazer as implementações usandodefimpl para o nosso caso de aceitar Listas e Maps como argumentos:

defimpl MyList, for: List do
  def first_item([item | _list]), do: item
end

defimpl MyList, for: Map do
  def first_item(map) do
    map
    |> Enum.to_list()
    |> List.first()
  end
end


결론



Com Protocolos nós podemos definir diferentes tipos de comportamentos para uma determinada função, semper se baseando no tipo de dado que queremos processar.

Um bom exemplo de cenário real para isso é o próprio Jason que usamos para transformar as respostas da nossa aplicação web.

O mesmo possui um protocolo chamadoJason.Encoder , 인코딩 방법에 대한 논쟁이 있습니다. 부분적인 Desta 인터페이스 구현은 json에 의존하는 인코딩 팁을 다른 방식으로 구현합니다.

좋은 웹페이지 즐겨찾기