Elixir 宏:如何使用动态元数定义函数
Elixir macros: how to define function with dynamic arity
参考这个 post:。
上面的post问的是如何用宏生成无参数的函数,我想知道如何生成带参数的函数?
假设有一个宏warp
,我可以这样写代码:
warp fun, [args], :ok
然后它生成如下代码:
fun(args), do: :ok
这是一个非常简单的例子:
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"}
如果你想生成一个动态参数列表,你需要使用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}
参考这个 post:
上面的post问的是如何用宏生成无参数的函数,我想知道如何生成带参数的函数?
假设有一个宏warp
,我可以这样写代码:
warp fun, [args], :ok
然后它生成如下代码:
fun(args), do: :ok
这是一个非常简单的例子:
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"}
如果你想生成一个动态参数列表,你需要使用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}