【问题标题】:Elixir - Calling / Invoking Macros - UndefinedFunctionErrorElixir - 调用/调用宏 - UndefinedFunctionError
【发布时间】:2015-08-10 02:23:10
【问题描述】:

为什么 Elixir 在 .exs 文件中使用 Module.macroName 语法调用宏时会报告 UndefinedFunctionError?只有当我有另一个调用宏的函数并且我调用函数而不是宏时,我似乎才能调用宏。

下面的代码演示了这一点:

defmodule Sample do
  defmacro doIt(expression) do
    quote do
      IO.puts unquote(expression)
    end
  end

  def doFunc(e), do: doIt(e)
end

Sample.doFunc "Hello World via Function" # Works fine
Sample.doIt "Hello World from Macro!" # Gives error

输出

Hello World via Function
** (UndefinedFunctionError) undefined function: Sample.doIt/1
    Sample.doIt("Hello World from Macro!")
    (elixir) lib/code.ex:307: Code.require_file/2

Elixir documentation 示例使用iex,而不是在.exs 文件中调用宏。即使是上面的代码,如果我们删除对Sample.doIt 的调用并将其加载到iex,然后调用Sample.doIt 也可以正常工作。

E:\elixir>iex hello.exs
Hello World via Function
Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> require Sample
nil
iex(2)> Sample.doIt "Hello"
Hello
:ok
iex(3)>

如果我在上面的文件中尝试require Sample,如下所示

defmodule Sample
  ... rest of stuff as shown above ...
end

require Sample

Sample.doFunc "Hello World via Function"
Sample.doIt "Hello World from Macro!"

我收到错误

** (CompileError) hello.exs:11: module Sample is not loaded but was defined. This happens because you are trying to use a module in the same context it is defined. Try defining the module outside the context that requires it.
    (stdlib) lists.erl:1352: :lists.mapfoldl/3
    (stdlib) lists.erl:1353: :lists.mapfoldl/3

【问题讨论】:

    标签: elixir


    【解决方案1】:

    像往常一样,您需要在使用其宏之前需要一个模块,以向编译器表明模块的编译顺序:

    defmodule Other do
      def run do
        require Sample
    
        Sample.doFunc "Hello World via Function"
        Sample.doIt "Hello World from Macro!"
      end
    end
    
    Other.run # => Hello World via Function
              #    Hello World from Macro!
    

    【讨论】:

    • 在这里,您也在另一个模块中定义了一个函数 run 以使用 Sample.doIt - 这是使用宏的唯一方法 - 通过包含在模块
    • 这似乎是编译器的限制。正如错误所说 - 您不能在定义模块的相同上下文中使用模块中的宏。我猜这与编译器如何为编译排序有关。
    • 是的,完全正确。宏是在编译时展开的,所以当我们解析defmodule Foo后跟Foo.some_macro时,我们还没有编译Foo,所以我们不知道如何展开宏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 2013-09-16
    • 1970-01-01
    • 2023-03-05
    • 2021-03-03
    • 2018-10-26
    相关资源
    最近更新 更多