我一直在研究Elixir中的宏,然后我在编程Elixir>第20章>使用绑定注入值中找到这个片段。使用非引用的动态函数定义
defmodule Test do
require My
[ :fred, :bert ] |> Enum.each(&My.mydef(&1))
end
其中mydef
是一个简单的宏,它为给定的名称定义了一个echo方法。因此,我的模块测试应该有两个功能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文档,我们不能在使用bind_quoted
时使用unquote
。
有人可以解释Elixir如何处理该代码吗?
我原以为这是因为'def'是一个宏,那么在给宏参数传递给宏之前引用这个宏,所以'unquote'将被允许。但是,如果我尝试'My.mydef(unquote(name))',那么我会得到预期的错误。我认为有一些特殊的处理def参数。 –
的确如此,我们可以在宏的参数上使用unquote,但为了获得该参数的值,我们必须使用'Macro.escape(expr,unquote:true)'来移除引用的表达式以去除对'unquote'的调用' 。然后我们可以引用一个新的表达式,它将使用我们的引用表达式。然而,为了在调用者的上下文中插入它的值,我们必须记住'unquote'这个表达式,'unquote(name)'作为参数的值将是标识符'name'。 –
我可以回答这个问题,如果你请把它作为一个单一的问题,格式化。请删除答案,这绝不是答案,删除评论,将答案和注释的重要部分放入原始问题中,并将其作为[MCVE](https://stackoverflow.com/help/mcve )。 – mudasobwa