繁体   English   中英

Elixir宏,引用和取消引用

[英]Elixir macros, quoting and unquoting

我正在学习Elixir,并尝试使用Macro系统。
我正在尝试使变量可用于将由宏与其他代码包装在一起的块,但是我显然做错了什么。

这是我的起点宏,可以正常工作。 我知道在Elixir中有更多惯用的方法可以迭代,因此我将其写为练习:

defmodule Loops do
  defmacro times(n, [do: block]) do
    quote do
      Enum.each(1..unquote(n), fn(_) -> unquote(block) end)
    end
  end
end

import Loops

times 3 do
  IO.puts "Hello!"
end

现在,我要完成的工作就是能够从do块中引用计数器。 因此,如果我给fn参数起一个合适的名字:

Enum.each(1..unquote(n), fn(_) -> unquote(block) end)
# becomes:
Enum.each(1..unquote(n), fn(counter) -> unquote(block) end)

我希望能够做这样的事情:

times 3 do
  IO.puts "Hello! iteration n: #{counter}"
end

但是,由于undefined function counter/0因此无法正常工作并引发CompileError 我传递给宏调用do块引发了错误,我发现这有点违反直觉,因为我认为在调用unquote()时,该块将被放置在扩展代码中。

我是用错误的方式解决问题,还是根本不可能?

您可以使用Kernel.var!/2来使counter成为“不卫生的”变量。 这将确保生成的代码可用它,而不会被Elixir的宏系统重命名。

defmodule Loops do
  defmacro times(n, [do: block]) do
    quote do
      Enum.each(1..unquote(n), fn(var!(counter)) ->
        unquote(block)
      end)
    end
  end
end

defmodule Main do
  require Loops

  def main do
    Loops.times 3 do
      IO.puts "Hello! iteration n: #{counter}"
    end
  end
end

Main.main

输出:

Hello! iteration n: 1
Hello! iteration n: 2
Hello! iteration n: 3

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM