如何“splat”动态创建函数的函数参数

时间:2017-12-08 06:26:11

标签: macros elixir metaprogramming

我正在模块中生成一些函数:

    <style name="CalenderViewCustom" parent="Theme.AppCompat">
        <item name="colorAccent">@color/red</item>
        <item name="colorPrimary">@color/white</item>
    </style>

    <style name="CalenderViewDateCustomText" parent="android:TextAppearance.DeviceDefault.Small">
        <item name="android:textColor">@color/white</item>
        <item name="android:weekNumberColor">@color/red</item>
    </style>

    <style name="CalenderViewWeekCustomText" parent="android:TextAppearance.DeviceDefault.Small">
        <item name="android:textColor">@color/white</item>
    </style>

问题是生成的函数显然接受一个参数,即大小为2的列表:

defmodule M do
  funs = [do_it: [:arg1, :arg2]]

  Enum.each(funs, fn {name, args} ->
    args = Enum.map(args, & {&1, [], Elixir})
    def unquote(name)(unquote(args)),
      do: IO.inspect(unquote(args))
  end)
end

目标是动态声明接受两个参数的函数。在ruby术语中,它将是到unsplat 参数列表。

是否有可能在没有模式匹配▶ M.__info__(:functions) #⇒ [do_it: 1] 的结果AST并手动展平列表的情况下完成此操作?

1 个答案:

答案 0 :(得分:6)

您可以Kernel.SpecialForms.unquote_splicing/1使用&#34;拼接&#34;在args列表中:

defmodule M do
  funs = [do_it: [:arg1, :arg2], do_it: [:arg1, :arg2, :arg3]]

  Enum.each(funs, fn {name, args} ->
    def unquote(name)(unquote_splicing(args)), do: :ok
  end)
end
iex(1)> M.__info__(:functions)
[do_it: 2, do_it: 3]