我一直在研究Elixir中的宏,然后我在编程Elixir>中找到了这个片段。第20章>使用绑定来注入值。
defmodule Test do
require My
[ :fred, :bert ] |> Enum.each(&My.mydef(&1))
end
其中mydef
是一个简单的宏,它定义了给定名称的echo方法。因此,我的模块Test应该有两个函数fred
和bert
,然后作者解释bind_quoted
,并在宏中使用unquote
来定义函数,从而产生。
defmodule My do
defmacro mydef(name) do
quote bind_quoted: [name: name] do
def unquote(name)(), do: unquote(name)
end
end
end
作者已经说bind_quoted
将推迟unquote
执行,允许在运行时定义方法。然后我使用Macro.to_string来分析生成的内容,这指示我对此进行测试。
defmodule Test do
name = :something
def unquote(name)(), do: unquote(name)
end
Test.something()
# Returns :something
现在我想知道它是如何工作的。该代码应该抛出错误,告知unquote
未在quote
块中使用,而且对于宏mydef
几乎相同,根据Elixir文档,我们无法使用unquote
{ {1}}使用bind_quoted
。
有人可以解释Elixir如何处理该代码吗?
答案 0 :(得分:0)
我认为作者告诉我不解释Macro.escape
,它使用bind_quoted
绑定变量并同时禁用unquote
。因为,至少我不知道如何,只能为宏的某些部分禁用unquote是不可能的,那么必须要做。
由于宏参数在传递给宏之前被引用,我们可以使用我们想要的任何东西,但是取消引用将取决于宏处理的方式,即。例如,当我们在params
unquote
时,此代码会引发错误
defmacro print(str) do
quote do
IO.puts unquote(str)
end
end
print("Hello World")
# => :ok
str = "Hello again"
print(unquote(str))
# => unquote cannot be used outside quote
第二次打印调用将扩展为IO.puts(unquote(str))
并且出现错误。为了解决这个问题,我们必须转义参数的unquote,因为它是在Kernel.def中完成的 - 使用Macro.escape(expr,unquote:true)。