即使使用 Macro.escape,取消引用也不适用于地图

Unquoute not working for maps even with Macro.escape

我有以下代码:

defmodule Foo do
  defmacro __using__(options) do
    attrs = Keyword.get(options, :attrs, Macro.escape(%{}))
    quote do
      def show, do: IO.inspect(unquote(attrs))
    end
  end
end

defmodule MacroBug do
  use Foo,
    attrs: Macro.escape(%{:correct => true})
end

此代码打印:

iex(5)> MacroBug.show
{:%{}, [], [correct: true]}
{:%{}, [], [correct: true]}

应该是%{correct: false},不是吗?如果不是,正确的方法是什么

the documentation 所示,应该明确 Macro.escape/2 values.

在您的示例中,问题是您实际上两次引用了地图。检查这三个宏:

defmodule Escape do
  defmacro q(opts) do
    IO.inspect(opts, label: "quote")
    quote do: IO.inspect(unquote(opts), label: "unquote")
  end

  defmacro e(opts) do
    value = IO.inspect(Macro.escape(%{foo: %{}}), label: "escape")
    quote do: IO.inspect(unquote(value), label: "unescape")
  end

  defmacro e!(opts) do
    value = IO.inspect(%{foo: %{}}, label: "escape!")
    quote do: IO.inspect(unquote(value), label: "unescape!")
  end
end

前两个相当等价,并且很高兴地产生了预期的结果。

iex|1 ▸ Escape.q %{foo: %{}}
escape: {:%{}, [], [foo: {:%{}, [], []}]}
unescape: %{foo: %{}}
%{foo: %{}}
iex|2 ▸ Escape.q %{foo: %{}}
quote: {:%{}, [], [foo: {:%{}, [], []}]}
unquote: %{foo: %{}}
%{foo: %{}}

第三个,虽然,加注,因为不能通过 AST 转换边界 %{foo: %{}}。也就是说,对于后一种情况,就像在宏上下文中创建的值一样,应该对其进行转义。

对于从宏外部传递的值, 为您完成。