我有一个行为和一个函数,其中包含应该实现该行为的模块列表。我想检查传入的每个模块是否确实实现了该行为。我可以使用下面的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()
?
答案 0 :(得分:3)
有趣的问题。
关于“我想确保我实现了所需的一切”的行为是否比“我希望其他所有人都知道我实现了所需的一切”的行为更多?
我的理解是,行为是模块作者与该模块的用户之间的约定:“我希望您向我提供一个可以完成所有这些事情的模块”。因此,这是模块用户的责任。
行为功能的关键字为chmod u+x ./mkepoch
Start="2019 03 28 16 49 20"
./mkepoch $Start
的事实在我看来似乎是,通常定义行为的模块也是将消耗该行为的模块(换句话说,调用回调) 。行为实现者似乎有责任确保其正确实现行为,并进行编译时检查以帮助他们解决问题,但对于需要行为执行的模块的用户,则没有运行时帮助确保他们确实提供了有效的实现。
您提供运行时警告的解决方案对我来说看起来不错-但是可以在不提供1553788160
属性的情况下实现行为,因此在这种情况下将无法正常工作。
如果行为实现者在其代码中声明@callback
但忽略了编译器警告,则会出现一条稍微有用的错误消息:
警告:行为ExpectBehaviour所需的功能foo / 0未实现(在ClaimsItImplementsButDoesNot模块中)
@behaviour
但是,如果您只是传递一个不实现行为的不相关模块,情况并非如此:
@behaviour
在typespec中是否可以将行为用作类型?
一个行为不是一种类型,而是一系列功能的规范,一个模块可以实现多种行为,所以我认为这没有道理。如上所述,将行为的回调限制在定义其的模块中似乎是明智的。