Tracks
/
Elixir
Elixir
/
Lehrplan
/
Protocols
Pr

Protocols in Elixir

4 Übungen

Über Protocols

Protokolle sind:

  • Ein Mechanismus, um Polymorphismus zu erreichen.
  • Definiert mit defprotocol.
  • Implementiert für einen bestimmten Datentyp mit defimpl.

Eine große Stärke von Protokollen ist, dass die Implementierung eines Protokolls für einen bestimmten Datentyp nicht zusammen mit der Definition des Datentyps oder der Definition des Protokolls ausgeliefert werden muss. Dadurch lassen sich Bibliotheken schreiben, die ihre Nutzer leicht erweitern können, damit sie mit den eigenen Datentypen der Nutzer funktionieren, ohne die Bibliothek ändern zu müssen.

Implementieren

Protokolle können für alle Elixir-Typen implementiert werden: Tuple, Atom, List, BitString, Integer, Float, Function, PID, Map, Port, Reference, Any und Structs.

Protokolle können für mehrere Typen gleichzeitig implementiert werden:

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

Wenn du ein Protokoll für ein Struct direkt in dem Modul implementierst, das das Struct definiert, kannst du das Argument :for weglassen:

defmodule ShoppingCart do
  defstruct [:items]

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

Fallback auf Any

Standardmäßig löst der Aufruf eines Protokolls für einen Datentyp, für den es nicht implementiert wurde, einen Protocol.UndefinedError-Fehler aus:

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

Das lässt sich vermeiden, indem du eine Fallback-Implementierung bereitstellst, die in einem solchen Fall verwendet wird. Dazu setzt du beim Definieren des Protokolls das Modulattribut @fallback_to_any auf true und schreibst eine Implementierung für den Typ Any:

defprotocol Reversible do
  @fallback_to_any true
  def reverse(term)
end

defimpl Reversible, for: Any do
  def reverse(term) do
    term
  end
end

Beachte, dass es in den meisten Fällen die bessere Wahl ist, einen Fehler auszulösen, weil es schwierig ist, eine sinnvolle Annahme über ein Protokoll für alle Datentypen zu treffen.

Erwähnenswerte eingebaute Protokolle

  • Enumerable – die Funktionen aus den Modulen Enum und Stream arbeiten mit Datentypen, die dieses Protokoll implementieren.
  • Collectable – die Funktion Enum.into/2 verwendet dieses Protokoll, um ein Enumerable in eine Collection einzufügen.
  • Inspect – du kannst dieses Protokoll implementieren, um zu ändern, wie Kernel.inspect/2 einen bestimmten Datentyp als String darstellt.
  • String.Chars – du kannst dieses Protokoll implementieren, um zu ändern, wie Kernel.to_string/1 einen bestimmten Datentyp als String darstellt.
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab

Lerne Protocols

Das Üben ist gesperrt

Schalte 1 weitere Übung frei, um Protocols zu üben