【问题标题】:Elixir macros: how to define function with dynamic arityElixir 宏:如何使用动态参数定义函数
【发布时间】:2016-01-08 03:57:21
【问题描述】:

参考这篇文章:How to create a dynamic function name using Elixir macro?

上面的帖子问了如何使用宏生成不带参数的函数,但我想知道如何生成带参数的函数?

假设有一个宏warp,我可以写如下代码:

warp fun, [args], :ok

然后生成如下代码:

fun(args), do: :ok

【问题讨论】:

  • 我很难找到有关“unquote_splicing”的文档。标题更改可能会帮助像我这样的未来谷歌人。

标签: macros elixir


【解决方案1】:

如果要生成参数的动态列表,需要使用unquote_splicing,像这样:

defmacro warp(name, argument_names, code) do
  quote do
    def unquote(name)(unquote_splicing(argument_names)) do
      unquote(code)
    end
  end
end

然后:

warp :foo, [a, b], {:ok, a, b}

生成:

def foo(a, b), do: {:ok, a, b}

如果你调用它会产生:

foo(1, 2)
# {:ok, 1, 2}

您也可以在没有unquote_splicing 的情况下像这样定义宏,并将组合名称和参数传递给def

defmacro warp(name_and_args, do: code) do
  quote do
    def unquote(name_and_args) do
      unquote(code)
    end
  end
end

这意味着您需要像调用def 一样调用warp,例如:

warp foo(a, b), do: {:ok, a, b}

【讨论】:

  • 这太酷了,很好的回答。但是,如果我们确实想像定义(您的最后一行)一样调用它,但不是以单行代码 , do: *1-line-only* 形式(又名:warp foo(a, b) do ... end
  • 没关系。我很确定它会“正常工作”。如果我理解正确,Elixir 将接受 , do: ...do ... end 完全相同的版本。 Ty 对于这个很棒的答案
  • @Bukov 是的,它只是语法糖,Elixir 很乐意接受这两种变体。谢谢你的好话
【解决方案2】:

这是一个非常简单的例子:

defmodule SomeMacro do
  defmacro warp(name, status) do
    quote do
      def unquote(name)(args) do
        {unquote(status), Enum.join(args, " - ")}
      end
    end
  end
end

defmodule SomeModule do
  require SomeMacro
  SomeMacro.warp :something, :ok
end

如果你像这样在 IEX 中运行它:

iex(1)> SomeModule.something([1,2,3])
{:ok, "1 - 2 - 3"}

iex(2)> SomeModule.something(["one", "two", "three"])
{:ok, "one - two - three"}

?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    • 2012-09-07
    • 2015-07-12
    • 2011-02-22
    • 2020-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多