检查模块是否实现了行为

时间:2019-03-30 18:36:29

标签: elixir

我有一个行为和一个函数,其中包含应该实现该行为的模块列表。我想检查传入的每个模块是否确实实现了该行为。我可以使用下面的MyBehaviour.implemented_by?/1来做到这一点,但我想知道是否还有更直接的方法。

defmodule MyBehaviour do
  @callback do_something(String.t(), String.t()) :: no_return()

  def implemented_by?(module) do
    :attributes
    |> module.module_info()
    |> Enum.member?({:behaviour, [__MODULE__]})
  end
end

这是最好的检查方法吗?我在文档或Elixir论坛或任何地方都找不到任何内容。

我什至要检查吗?还是应该让责任完全落在呼叫者身上?行为比“我希望其他所有人都知道我实现了所需要的一切”更多地是关于“我想确保实现了所需要的一切”?

在typespec中是否可以使用行为作为类型?我的函数规范可以说args应该实现我的行为,还是应该只使用module()/atom()

1 个答案:

答案 0 :(得分:3)

有趣的问题。

  

关于“我想确保我实现了所需的一切”的行为是否比“我希望其他所有人都知道我实现了所需的一切”的行为更多?

我的理解是,行为是模块作者与该模块的用户之间的约定:“我希望您向我提供一个可以完成所有这些事情的模块”。因此,这是模块用户的责任。

行为功能的关键字为chmod u+x ./mkepoch Start="2019 03 28 16 49 20" ./mkepoch $Start 的事实在我看来似乎是,通常定义行为的模块也是将消耗该行为的模块(换句话说,调用回调) 。行为实现者似乎有责任确保其正确实现行为,并进行编译时检查以帮助他们解决问题,但对于需要行为执行的模块的用户,则没有运行时帮助确保他们确实提供了有效的实现。

您提供运行时警告的解决方案对我来说看起来不错-但是可以在不提供1553788160 属性的情况下实现行为,因此在这种情况下将无法正常工作。

如果行为实现者在其代码中声明@callback但忽略了编译器警告,则会出现一条稍微有用的错误消息:

  

警告:行为ExpectBehaviour所需的功能foo / 0未实现(在ClaimsItImplementsButDoesNot模块中)

@behaviour

但是,如果您只是传递一个不实现行为的不相关模块,情况并非如此:

@behaviour
  

在typespec中是否可以将行为用作类型?

一个行为不是一种类型,而是一系列功能的规范,一个模块可以实现多种行为,所以我认为这没有道理。如上所述,将行为的回调限制在定义其的模块中似乎是明智的。