Behaviourで共通の機能を実装する
ElixirにはBehaviourという機能があり、共有する機能(関数)を定義することができる。
定義したBehaviourをモジュールに実装することで、定義に沿った関数の実装を行うことができる。
Behaviourの定義
Behaviourを定義する際には通常のモジュールの作成に加え、@callback
によって共有する関数の名前と戻り値を定義する。
defmodule Action do
@callback say(name: String.t()) :: String.t()
end
Behaviourの実装
定義したBehaviourを他のモジュールに実装するためには、@behaviour
によって実装するBehaviourを指定する。
defmodule Dog do
@behaviour Action
def say(name), do: "#{name}: わんわん!"
end
実装するモジュールで構造体を定義した場合
Elixirの構造体はモジュールであるため、構造体の定義と一緒に記述することができる。
defmodule Cat do
defstruct [:name]
@behaviour Action
def say(name), do: "#{name}: にゃーん!"
end
しかしこの場合は「構造体にBehaivourを実装している」とは言わない。
まずElixirの構造体は、Rustなどの構造体とは全く異なるものものである。
Rustの構造体は、traitとimplによって共通の関数を実装することができるので、
オブジェクト指向言語のクラスに近い使い方をすると言える。
これに対してElixirの構造体は、定義されたキーを持つマップである。
つまりインスタンス = %構造体{}
から生成したインスタンスはマップであり、そのためインスタンス.関数()
のように関数を呼び出すことができない。
よってElixirではモジュールから関数を呼び出すことはできるが、構造体から呼び出すことはできない。
それは、構造体のフィールドへのアクセスが構造体.キー
であり、マップから関数を呼び出せないからでもある。
またそれはis_map(インスタンス)
を実行することで理解することができる。