如何使用 Elixir 宏创建动态函数名?
How to create a dynamic function name using Elixir macro?
我想动态创建函数名称。我写了这个宏
defmacro generate_dynamic(name) do
quote do
def add_(unquote(name)) do
end
end
end
我是这样使用的:
defmodule AnotherModule do
generate_dynamic :animal
end
现在,我只定义了 AnotherModule.add_
函数,而我期望 AnotherModule.add_animal
函数。
要实现此目的,您可以在 取消引用之前将 :add_
添加到名称前。此外,在这种情况下,方法名称后的括号是为了防止歧义。这应该可以解决问题:
defmacro generate_dynamic(name) do
quote do
def unquote(:"add_#{name}")() do
# ...
end
end
end
有时,作为一种有用的快捷方式,您可以内联获得相同的结果,而无需使用 unquote 片段编写宏。
defmodule Hello do
[:alice, :bob] |> Enum.each fn name ->
def unquote(:"hello_#{name}")() do
IO.inspect("Hello #{unquote(name)}")
end
end
end
Hello.hello_bob # => "Hello bob"
Hello.hello_alice # => "Hello alice"
我在要点上做了同样的事情来尝试模仿 Ruby 的 attr_accessor
:
defmodule MacroExp do
defmacro attr_accessor(atom) do
getter = String.to_atom("get_#{atom}")
setter = String.to_atom("set_#{atom}")
quote do
def unquote(getter)(data) do
data |> Map.from_struct |> Map.get(unquote(atom))
end
def unquote(setter)(data, value) do
data |> Map.put(unquote(atom), value)
end
end
end
defmacro attr_reader(atom) do
getter = String.to_atom("get_#{atom}")
quote do
def unquote(getter)(data) do
data |> Map.from_struct |> Map.get(unquote(atom))
end
end
end
end
defmodule Calculation do
import MacroExp
defstruct first: nil, second: nil, operator: :plus
attr_accessor :first # defines set_first/2 and get_first/1
attr_accessor :second # defines set_second/2 and get_second/1
attr_reader :operator # defines set_operator/2 and get_operator/1
def result(%Calculation{first: first, second: second, operator: :plus}) do
first + second
end
end
我想动态创建函数名称。我写了这个宏
defmacro generate_dynamic(name) do
quote do
def add_(unquote(name)) do
end
end
end
我是这样使用的:
defmodule AnotherModule do
generate_dynamic :animal
end
现在,我只定义了 AnotherModule.add_
函数,而我期望 AnotherModule.add_animal
函数。
要实现此目的,您可以在 取消引用之前将 :add_
添加到名称前。此外,在这种情况下,方法名称后的括号是为了防止歧义。这应该可以解决问题:
defmacro generate_dynamic(name) do
quote do
def unquote(:"add_#{name}")() do
# ...
end
end
end
有时,作为一种有用的快捷方式,您可以内联获得相同的结果,而无需使用 unquote 片段编写宏。
defmodule Hello do
[:alice, :bob] |> Enum.each fn name ->
def unquote(:"hello_#{name}")() do
IO.inspect("Hello #{unquote(name)}")
end
end
end
Hello.hello_bob # => "Hello bob"
Hello.hello_alice # => "Hello alice"
我在要点上做了同样的事情来尝试模仿 Ruby 的 attr_accessor
:
defmodule MacroExp do
defmacro attr_accessor(atom) do
getter = String.to_atom("get_#{atom}")
setter = String.to_atom("set_#{atom}")
quote do
def unquote(getter)(data) do
data |> Map.from_struct |> Map.get(unquote(atom))
end
def unquote(setter)(data, value) do
data |> Map.put(unquote(atom), value)
end
end
end
defmacro attr_reader(atom) do
getter = String.to_atom("get_#{atom}")
quote do
def unquote(getter)(data) do
data |> Map.from_struct |> Map.get(unquote(atom))
end
end
end
end
defmodule Calculation do
import MacroExp
defstruct first: nil, second: nil, operator: :plus
attr_accessor :first # defines set_first/2 and get_first/1
attr_accessor :second # defines set_second/2 and get_second/1
attr_reader :operator # defines set_operator/2 and get_operator/1
def result(%Calculation{first: first, second: second, operator: :plus}) do
first + second
end
end