首页 > 解决方案 > 我可以在 Elixir 中另一个宏的引用中扩展一个宏吗?

问题描述

给定下面的代码,该行在using (opts) as opts内use Composite, user_opts: user_opts结束。有没有办法将该代码注入外部宏中?[{:user_opts, [line: 3, counter: {MockUserNode1, 2}], Automaton.Node}]

defmacro __using__(user_opts) do
    a =
      if Enum.member?(Composite.types(), user_opts[:node_type]) do
        IO.inspect(user_opts)

        quote bind_quoted: [user_opts: user_opts] do
          use DynamicSupervisor
          use Composite, user_opts: user_opts
        end
      else
        quote do: use(Action)
      end
end

标签: macroselixirmetaprogramming

解决方案


回答所说的问题:完全可以从其他宏内部调用宏,最后只是递归地注入 AST。

defmodule DeeplyUsed do
  defmacro __using__(opts) do
    quote bind_quoted: [opts: opts] do
      opts
    end
  end
end

defmodule Used do
  defmacro __using__(opts) do
    quote bind_quoted: [opts: opts] do
      use DeeplyUsed, opts: opts
    end
  end
end

defmodule Using do
  use Used, line: 3, counter: {MockUserNode1, 2}
end

也就是说,你的问题是诱发的。


旁注: [{:user_opts, _, Automaton.Node}]那里看起来确实很可疑,这不是关键字列表的引用方式。从显式取消引用记录到user_opts那里的内容开始。

defmacro __using__(user_opts) do
  IO.inspect(user_opts, label: "Outside")
  quote do
    IO.inspect(unquote(user_opts), label: "Inside")
    use Composite, user_opts: unquote(user_opts)
  end
end

推荐阅读