我试图在模块上已经定义的函数的基础上定义一个函数。
我想做这样的事情:
defmodule A do
def my_func(pid, arg1, arg2) do
send pid, "Do Something"
end
end
在定义my_func之后,我想定义my_func(arg1, arg2)
,它调用my_func
,传递一个pid,例如,我将从一个pid池中获得该pid。
我的第一次尝试是使用@on_definition,但没有成功。然后我试着在模块内这样做:
Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
args = Enum.map(0..arity-1, fn i -> "arg_#{i}" end)
quoted = quote do
def unquote(func_name)(unquote_splicing(args)) do
....
但我仍然没有成功。有人知道我该怎么做吗?:(
您可以这样完成:
defmodule Test do
def my_func(pid, arg1, arg2) do
send pid, {arg1, arg2}
end
quoted = Enum.map Module.definitions_in(__MODULE__, :def), fn {func_name, _arity} ->
quote do
def unquote(func_name)(arg1, arg2) do
pid = :some_pid
unquote(func_name)(pid, arg1, arg2)
end
end
end
Module.eval_quoted(__MODULE__, quoted)
Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
IO.inspect {func_name, arity}
end
end
如果您使用elixirc test.ex
编译它,您将看到它吐出my_func/2
和my_func/3
的定义。初始代码的问题是,当您映射并引用定义时,您从未评估过那些引用的表达式,因此它们没有作为模块的一部分进行编译。
实际上,bitwalker的解决方案可以简化。您不需要引用并执行eval_quoted
,因为def
是一个直接注入AST的宏。所以这也会起作用:
defmodule Test do
def my_func(pid, arg1, arg2) do
send pid, {arg1, arg2}
end
Enum.map Module.definitions_in(__MODULE__, :def), fn {func_name, _arity} ->
def unquote(func_name)(arg1, arg2) do
pid = :some_pid
unquote(func_name)(pid, arg1, arg2)
end
end
Enum.each Module.definitions_in(__MODULE__, :def), fn {func_name, arity} ->
IO.inspect {func_name, arity}
end
end