bind_quoted不会在def内创建绑定

时间:2018-10-20 02:34:34

标签: macros elixir

bind_quoted似乎不适合我。这是一个不使用bind_quoted且可以正常使用的示例:

defmodule Animals do

  defmacro dog do
    x = 4 

    quote do
      def go do
        IO.puts unquote(x)
      end
    end

  end

end

defmodule Test do
  require Animals
  Animals.dog  #inject the definition of go() into the Test module
end

在iex中:

iex(10)> c "a.exs"
warning: redefining module Animals (current version defined in memory)
  a.exs:1

warning: redefining module Test (current version defined in memory)
  a.exs:15

[Test, Animals]

iex(11)> Test.go  
4
:ok

iex(12)>

但是bind_quoted docs说:

  

...每次有人希望使用:bind_quoted选项时,   在引号中插入一个值。

好吧,让我们保持一致:

defmodule Animals do

  defmacro dog do
    x = 4 

    quote bind_quoted: [x: x] do
      def go do
        IO.puts x
      end
    end

  end

end

defmodule Test do
  require Animals
  Animals.dog  #inject go() into the Test module
end

在iex中编译:

iex(10)> c "a.exs"
warning: redefining module Animals (current version defined in memory)
  a.exs:1

warning: redefining module Test (current version defined in memory)
  a.exs:15

warning: variable "x" does not exist and is being expanded to "x()", please use parentheses to remove the ambiguity or change the variable name
  a.exs:17


== Compilation error in file a.exs ==
** (CompileError) a.exs:17: undefined function x/0 
    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
** (CompileError)  compile error
    (iex) lib/iex/helpers.ex:183: IEx.Helpers.c/2
iex(10)> 

错误报告中的相关消息是:

warning: variable "x" does not exist

为什么不呢?

1 个答案:

答案 0 :(得分:1)

通常,是的。这就是它的工作方式。但是def调用本身是一个宏,因此您仍然需要在其中使用unquote。如果您直接引用IO.puts,它将毫无问题地发挥作用。

这是演示代码的略微修改版本:

defmodule Animals do
  defmacro dog do
    x = 4

    quote(bind_quoted: [xx: x]) do
      IO.puts(xx)
    end
  end
end

defmodule Test do
  require Animals

  def go do
    Animals.dog
  end
end

现在返回您的实现;在此示例中,我将x绑定到xx上以明确向您显示,如果您尝试在此处取消对x的引用(而不是xx),则会引发编译错误:

defmodule Animals do
  defmacro dog do
    x = 4

    quote(bind_quoted: [xx: x]) do
      def go do
        IO.puts(unquote(xx))
      end
    end
  end
end