簡體   English   中英

為動態生成的宏加雙引號

[英]Double unquoting for dynamically generated macros

給定以下內容:

  for fn_name <- [:foo, :bar, :baz] do
    defmacro unquote(fn_name)(do: inner) do
      fn_name = unquote(fn_name) # <--- Why?
      quote do
        IO.puts "#{unquote(fn_name)} called"
        unquote(inner)
      end
    end
  end

fn_name = unquote(fn_name)的原因是什么? 如果我省略此行,則為編譯錯誤。 這種“雙重”取消報價的原因是什么?

讓我們稍微簡化一下示例:

for fn_name <- [:foo, :bar, :baz] do
  defmacro unquote(fn_name)(do: inner) do
    fn_name = unquote(fn_name) # <--- Why?
    quote do
      {unquote(fn_name), unquote(inner)}
    end
  end
end

在上面的示例中,因為quote返回帶有兩個未引用元素的元組,所以它等效於:

for fn_name <- [:foo, :bar, :baz] do
  defmacro unquote(fn_name)(do: inner) do
    fn_name = unquote(fn_name) # <--- Why?
    {fn_name, inner}
  end
end

現在,更容易理解如果您之前不unquote(fn_name)會發生什么:宏定義內根本就不存在變量fn_name 請記住,所有def (def,defp,defmacro等)都會啟動一個新的變量作用域,因此,如果要在內部使用fn_name,則需要以某種方式對其進行定義。

我們在此代碼中看到的另一個屬性是Elixir在看到quote時將停止取消quote 因此在上面的報價, unquote的宏定義,而是在執行宏,這也解釋了為什么需要變量的宏內部被定義時,不會加引號。

這是因為衛生

長生不老葯有宏觀衛生學的概念。 衛生意味着您在宏中定義的變量,導入和別名不會泄漏到調用者自己的定義中。

for fn_name <- [:foo, :bar, :baz] do
    defmacro unquote(fn_name)(do: inner) do
      fn_name = unquote(fn_name) # <-- This is macro's context
      quote do
        IO.puts "#{unquote(fn_name)} called" # <-- This is caller's context
        unquote(inner)
      end
    end
  end

您應該從Chris McCord的Metaprogramming Elixir書中閱讀“ 衛生保護呼叫者的上下文

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM