行为

行为 属于 Elixir

1 个练习

关于 行为

Behaviours 允许我们在一个 _behaviour 模块_中定义接口(一组函数和宏),这些接口之后可以由不同的_回调模块_实现。得益于共享的接口,这些回调模块可以互换使用。

Note

注意“behaviours”的英式拼写。

定义 behaviour

要定义 behaviour,我们需要创建一个新模块,并指定属于所需接口的函数列表。每个函数都需要使用 @callback 模块属性来定义。语法与函数类型规格(@spec)完全相同。我们需要指定函数名、实参类型列表以及所有可能的返回类型。

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

实现 behaviour

要向我们的模块添加已有的 behaviour(创建回调模块),我们使用 @behaviour 模块属性。它的值应该是我们要添加的 behaviour 模块的名称。

然后,我们需要定义该 behaviour 模块要求的所有函数(回调)。如果我们要实现别人的 behaviour,比如 Elixir 内置的 Access 或 GenServer behaviour,可以在 hexdocs.pm 的文档中找到该 behaviour 所有回调的列表。

回调模块并不局限于只实现其 behaviour 中的函数。单个模块也可以实现多个 behaviour。

要标明某个函数来自哪个 behaviour,我们应在每个函数前使用模块属性 @impl。它的值应该是定义该回调的 behaviour 模块的名称。

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

默认回调实现

定义 behaviour 时,可以为某个回调提供默认实现。这个实现应定义在 __using__/1 宏的 quoted 表达式中。为了让 behaviour 模块的使用者能够覆盖默认实现,请在函数实现之后调用 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 宏中导入它们。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 行为