Tracks
/
Elixir
Elixir
/
Lehrplan
/
Behaviours
Be

Behaviours in Elixir

1 Übung

Über Behaviours

Mit Behaviours können wir Schnittstellen (Mengen von Funktionen und Makros) in einem Behaviour-Modul definieren, die später von verschiedenen Callback-Modulen implementiert werden können. Dank der gemeinsamen Schnittstelle lassen sich diese Callback-Module austauschbar verwenden.

Note

Beachte die britische Schreibweise von „behaviours“.

Behaviours definieren

Um ein Behaviour zu definieren, müssen wir ein neues Modul erstellen und eine Liste von Funktionen angeben, die Teil der gewünschten Schnittstelle sind. Jede Funktion muss mit dem Modulattribut @callback definiert werden. Die Syntax ist identisch mit der einer Funktionstypspezifikation (@spec). Wir müssen einen Funktionsnamen, eine Liste von Argumenttypen und alle möglichen Rückgabetypen angeben.

defmodule Countable do
  @callback count(collection :: any) :: pos_integer
end

Behaviours implementieren

Um unserem Modul ein vorhandenes Behaviour hinzuzufügen (ein Callback-Modul zu erstellen), verwenden wir das Modulattribut @behaviour. Sein Wert sollte der Name des Behaviour-Moduls sein, das wir hinzufügen.

Dann müssen wir alle Funktionen (Callbacks) definieren, die dieses Behaviour-Modul verlangt. Wenn wir ein Behaviour von jemand anderem implementieren, etwa die in Elixir eingebauten Behaviours Access oder GenServer, finden wir die Liste aller Callbacks des Behaviours in der Dokumentation auf hexdocs.pm.

Ein Callback-Modul ist nicht darauf beschränkt, nur die Funktionen zu implementieren, die Teil seines Behaviours sind. Es ist auch möglich, dass ein einzelnes Modul mehrere Behaviours implementiert.

Um zu kennzeichnen, welche Funktion aus welchem Behaviour stammt, sollten wir vor jeder Funktion das Modulattribut @impl verwenden. Sein Wert ist der Name des Behaviour-Moduls, das diesen Callback definiert.

defmodule BookCollection do
  @behaviour Countable

  defstruct [:list, :owner]

  @impl Countable
  def count(collection) do
    Enum.count(collection.list)
  end

  def mark_as_read(collection, book) do
    # other function unrelated to the Countable behaviour
  end
end

Standardimplementierungen von Callbacks

Beim Definieren eines Behaviours ist es möglich, eine Standardimplementierung für einen Callback anzugeben. Diese Implementierung sollte im quoted expression des Makros __using__/1 definiert werden. Damit Nutzer des Behaviour-Moduls die Standardimplementierung überschreiben können, sollten wir nach der Funktionsimplementierung das Makro defoverridable/1 aufrufen. Es erwartet eine Keyword-Liste, in der Funktionsnamen die Schlüssel und die Stelligkeiten der Funktionen die Werte sind.

defmodule Countable do
  @callback count(collection :: any) :: pos_integer

  defmacro __using__(_) do
    quote do
      @behaviour Countable
      def count(collection), do: Enum.count(collection)
      defoverridable count: 1
    end
  end
end

Beachte, dass es nicht empfehlenswert ist, Funktionen in __using__/1 zu definieren, außer um Standardimplementierungen von Callbacks bereitzustellen. Du kannst Funktionen aber jederzeit in einem anderen Modul definieren und sie im Makro __using__/1 importieren.

Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab

Lerne Behaviours