我试图在defmacro
内定义动态函数,但无法理解函数本身内部函数值不可用的原因
defmacro __using__(_) do
Enum.each ~w(public private), fn value ->
def unquote(:"make_#{value}")(user = %User{}) do
%{user | privacy: value}
end
end
end
Elixir默认情况下会value
扩展为value()
,然后说没有这样的功能
答案 0 :(得分:0)
您错过quote
周围的def
。您还需要在def
内的地图更新表达式中取消引用该值。最后,您需要在此使用Enum.map
而不是Enum.each
,以便__using__/1
返回构建的AST:
defmacro __using__(_) do
Enum.map ~w(public private), fn value ->
quote do
def unquote(:"make_#{value}")(user = %User{}) do
%{user | privacy: unquote(value)}
end
end
end
end
测试:
defmodule User do
defstruct [:privacy]
end
defmodule A do
defmacro __using__(_) do
Enum.map ~w(public private), fn value ->
quote do
def unquote(:"make_#{value}")(user = %User{}) do
%{user | privacy: unquote(value)}
end
end
end
end
end
defmodule B do
use A
end
iex(1)> %User{} |> B.make_public
%User{privacy: "public"}
编辑:评论中要求的更改:
defmacro __using__(_) do
Enum.map ~w(public private), fn value ->
quote do
def unquote(:"make_#{value}")(user = %User{}) do
%{user | privacy: unquote(value)}
end
def unquote(:"make_#{String.upcase(value)}")(user = %User{}) do
%{user | privacy: unquote(String.upcase(value))}
end
end
end
end
iex(1)> %User{} |> B.make_public
%User{privacy: "public"}
iex(2)> %User{} |> B.make_PUBLIC
%User{privacy: "PUBLIC"}
iex(3)> %User{} |> B.make_private
%User{privacy: "private"}
iex(4)> %User{} |> B.make_PRIVATE
%User{privacy: "PRIVATE"}