ビヘイビアを使うと、_ビヘイビアモジュール_の中でインターフェース(関数とマクロの集まり)を定義できます。これを後から別々の_コールバックモジュール_で実装できます。インターフェースを共有しているおかげで、これらのコールバックモジュールは互いに置き換えて使うことができます。
「behaviours」はイギリス英語のつづりであることに注意してください。
ビヘイビアを定義するには、新しいモジュールを作成し、必要なインターフェースに含まれる関数の一覧を指定します。各関数は、モジュール属性@callbackを使って定義します。構文は関数の型仕様(@spec)とまったく同じです。指定するのは、関数名、引数の型の一覧、そして取りうる戻り値の型すべてです。
defmodule Countable do
@callback count(collection :: any) :: pos_integer
end
既存のビヘイビアを自分のモジュールに追加する(コールバックモジュールを作る)には、モジュール属性@behaviourを使います。値には、追加するビヘイビアモジュールの名前を指定します。
次に、そのビヘイビアモジュールが要求する関数(コールバック)をすべて定義します。Elixirに組み込みのAccessやGenServerなど、他の人が作ったビヘイビアを実装する場合は、そのビヘイビアのコールバックの一覧がhexdocs.pmのドキュメントに載っています。
コールバックモジュールは、自分のビヘイビアに含まれる関数だけを実装しなければならないわけではありません。1つのモジュールで複数のビヘイビアを実装することもできます。
どの関数がどのビヘイビア由来なのかを示すには、各関数の前にモジュール属性@implを付けます。値には、そのコールバックを定義しているビヘイビアモジュールの名前を指定します。
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
ビヘイビアを定義するときは、コールバックのデフォルト実装を用意できます。この実装は、__using__/1マクロのquote式の中に定義します。ビヘイビアモジュールを使う側がデフォルト実装を上書きできるようにするには、関数の実装のあとでdefoverridable/1マクロを呼びます。このマクロは、関数名をキー、関数のアリティを値とするキーワードリストを受け取ります。
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
__using__/1の中で関数を定義するのは、コールバックのデフォルト実装を定義する以外の目的ではおすすめしません。ただし、別のモジュールで関数を定義して、それを__using__/1マクロの中でインポートすることはいつでもできます。