Elixir 如何使用打字机和透析器?
在Elixir中,我如何记录函数将返回实现特定行为的模块 举一个简单的例子,假设我创建了一个由两个模块实现的Elixir 如何使用打字机和透析器?,elixir,Elixir,在Elixir中,我如何记录函数将返回实现特定行为的模块 举一个简单的例子,假设我创建了一个由两个模块实现的GreeterBehavior行为: defmodule GreeterBehaviour do @callback say_hello(String.t) :: String.t end defmodule FormalGreeter do @behaviour GreeterBehaviour def say_hello(name) do "Good day t
GreeterBehavior
行为:
defmodule GreeterBehaviour do
@callback say_hello(String.t) :: String.t
end
defmodule FormalGreeter do
@behaviour GreeterBehaviour
def say_hello(name) do
"Good day to you #{name}"
end
end
defmodule CasualGreeter do
@behaviour GreeterBehaviour
def say_hello(name) do
"Hey #{name}"
end
end
然后,我想通过一个函数检索迎宾员,轻松地替换掉这些实现中的任何一个:
defmodule MyApp do
def main do
greeter().say_hello("Pete") |> IO.puts
end
@spec greeter() :: GreeterBehaviour # This doesn't work with dialyzer
def greeter do
FormalGreeter # Can easily be swapped to CasualGreeter
end
end
透析器将成功检查临时迎宾员
和正式迎宾员
是否正确执行迎宾员行为
行为。但是,如何定义类型规范,以便透析器检查greeter/0
返回的模块是否实际实现了GreeterBehavior
使用@spec greeter()::greeterbehavior
不起作用,因为透析器会发出警告:
lib/my_app.ex:19: Invalid type specification for function 'Elixir.MyApp':greeter/0. The success typing is () -> 'Elixir.FormalGreeter'
在您的行为中,您可以定义一个类型,用于
打招呼
:
@type f :: (String.t() -> String.t())
您的迎宾员
函数可以返回一个模块+函数:&module.say_hello/1
规范是:
@spec greeter() :: GreeterBehaviour.f()
这是一个好问题,我不确定是否可以在typespec中指定行为,我认为您可以将其作为spec
@spec greeter()::FormalGreeter
,以便透析器知道您返回的确切模块(在您的情况下,即使没有规范,它也会知道)然后,它可能会检查您是否正在调用不存在的模块上的函数;我也希望是这样。投票支持此功能。我不确定类型规格,但我倾向于使用配置(config:my\u app,greeter\u module:FormalGreeter
)@DerekKraan我认为这是一个激励性的例子,可以解释为什么这样做会很好,例如,如果在配置文件中配置了错误的模块,则可以捕获。
defmodule GreeterBehaviour do
@type f :: (String.t() -> String.t())
@callback say_hello(String.t()) :: String.t()
end
defmodule FormalGreeter do
@behaviour GreeterBehaviour
def say_hello(name) do
"Good day to you #{name}"
end
end
defmodule CasualGreeter do
@behaviour GreeterBehaviour
def say_hello(name) do
"Hey #{name}"
end
end
defmodule MyApp do
def main do
greeter().("Pete") |> IO.puts()
end
# This will work with dialyzer
@spec greeter() :: GreeterBehaviour.f()
def greeter do
# Can easily be swapped to CasualGreeter
&FormalGreeter.say_hello/1
end
end