Elixir中的源代码生成

时间:2016-07-18 17:04:47

标签: elixir

我目前正在学习/阅读元编程灵药 我设法生成一个函数,使用宏来设置它的名称:

defmodule MyMacros do
  defmacro fun_gen(name) do
    atom_name = elem(name, 0)
    str_name = atom_name |> to_string
    quote do
      def unquote(name) do
        IO.puts unquote(str_name)
      end
    end
  end
end

defmodule My do
  require MyMacros
  MyMacros.fun_gen(bar)
end

结果:

iex(1)> My.bar
bar
:ok

所以这很棒:)但我想知道是否可以使用Enum.each或类似的东西生成几个函数:

defmodule MyMacros do
  defmacro fun_gen(name) do
    atom_name = elem(name, 0)
    str_name = atom_name |> to_string
    quote do
      def unquote(name) do
        IO.puts unquote(str_name)
      end
    end
  end
end

defmodule My do
  require MyMacros
  loop (~w(foo bar baz) do
    MyMacros.fun_gen(item)
  end
end

有没有一种循环方式来生成源代码? 谢谢!

1 个答案:

答案 0 :(得分:3)

你可以在不使用宏的情况下完成它:

 defmodule My do

  @methods ~w|one two three|a

  for method <- @methods do
    def unquote(method)() do
      IO.puts unquote(method)
    end
  end

end

产生

iex> My.one
one
iex> My.two
two

或者使用宏:

defmodule MyMacros do
  defmacro gen_funs(names) do
    for name <- names do
      quote do
        def unquote(name)() do
          IO.puts unquote(name)
        end
      end
    end
  end
end

defmodule My2 do
  require MyMacros
  MyMacros.gen_funs([:one, :two, :three])
end

产生

iex> My2.one
one
iex> My2.two
two

注意:我们将列表直接传递给gen_funs而不是sigil或包含列表的变量。我们必须这样做,因为宏接收引用的参数。这就是为什么你必须在宏中而不是使用宏的模块中进行循环。