我想创建一个函数,并将其嵌入到其他模块中。而不需要在这些产品中重新实施。. 会是这样的。
defmodule MyModuleWithFunction do
def my_function(m) do
IO.puts("***my name: #{__MODULE__}. My current value: #{m.var1}")
end
end
# usage 1
defmodule M1 do
def var1 do
"M1 var1"
end
# somehow embed my_function() here without having to re-implement it
end
# usage 2
defmodule M2 do
def var1 do
"M2 var1"
end
# somehow embed my_function() here without having to re-implement it
end
defmodule Main do
def print_data do
M1.my_function()
M2.my_function()
end
end
===>
"***my name: M1. My current value: M1 var1"
"***my name: M2. My current value: M2 var1"
我知道行为和协议。然而,我如何才能 嵌入 my_function
在其他模块中,并使其以所需的方式工作?
回答标题中的问题。
动态调度 酏剂 可与 Kernel.apply/3
.
小心。 我强烈不鼓励你这样做 除非你完全明白它是如何工作的。
要获得访问 __MODULE__
变量的方式,你需要注入AST,而不是调用函数。也就是说,你需要的是一个宏,而不是一个常规函数。
defmodule Injected do
defmacro yo do
caller = __CALLER__.module
quote do
IO.puts("***my name: #{unquote(caller)}. My current value: #{unquote(caller).var}")
end
end
end
而且,在目标模块中。
defmodule M do
def var do
"M1 var1"
end
import Injected
def test, do: yo()
end
这使得它可以 召唤 你在一个模块内部的功能,但不是从外部,因为函数和宏都会被导入为 私人.
为了达到需要的目的,我们可以使用 Kernel.use/2
.
defmodule Used do
defmacro __using__(_) do
caller = __CALLER__.module
quote do
def yo do
IO.puts("***my name: #{unquote(caller)}. My current value: #{unquote(caller).var}")
end
end
end
end
defmodule M do
use Used
def var do
"M1 var1"
end
end
M.yo()
#⇒ ***my name: Elixir.M. My current value: M1 var1