Elixir - 通过元编程定义模块中的函数

She*_*yar 5 metaprogramming elixir

我的模块中有三个相同的方法,它们做(几乎)完全相同的事情。我没有重复函数定义,而是尝试定义它们一次,以保持代码最少并且所有函数都相同。

到目前为止我已经尝试使用Code.eval_string

defmodule MyModule do
  Enum.each ~w(method1 method2 method3), fn method ->
    @method method

    Code.eval_string """
      def #{@method}(map) when is_map(map) do
        do_map_stuff(:#{@method}, map)
      end

      def #{@method}(arg) do
        do_other_stuff(:#{@method}, arg)
      end
    """
  end

  ## Other Methods

end
Run Code Online (Sandbox Code Playgroud)

但这会抛出ArgumentError

Compiling 1 file (.ex)
** (ArgumentError) cannot invoke def/2 outside module
    (elixir) lib/kernel.ex:4297: Kernel.assert_module_scope/3
    (elixir) lib/kernel.ex:3299: Kernel.define/4
    (elixir) expanding macro: Kernel.def/2
    nofile:1: (file)
Run Code Online (Sandbox Code Playgroud)

我认为引用/取消引用可能是可行的方法,但我不太确定如何使用它们来做到这一点(我已经阅读了Elixir 网站上的元指南)。

ror*_*rra 4

像这样的东西吗?

defmodule MyModule do
  def do_map_stuff(method, arg) do
    IO.inspect([method, arg])
  end

  Enum.each [:method1, :method2, :method3], fn method ->
    def unquote(method)(map) when is_map(map) do
      do_map_stuff(unquote(method), map)
    end

    def unquote(method)(arg)  do
      do_map_stuff(unquote(method), arg)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)