如何在模块上先前定义的函数的基础上定义函数



我试图在模块上已经定义的函数的基础上定义一个函数。

我想做这样的事情:

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/2my_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

最新更新