Tại sao Elixir báo cáo UndefinedFunctionError
khi gọi macro bằng cú pháp Module.macroName
trong tệp .exs
? Tôi dường như có thể gọi Macro chỉ khi tôi có một chức năng khác gọi macro và tôi gọi hàm thay vì macro.Elixir - Gọi/Gọi macro - Không xác địnhFunctionError
Dưới đây đang chứng tỏ điều này:
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
Output
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
Ví dụ Elixir documentation sử dụng iex
, thay vì gọi vĩ mô trong file .exs
. Ngay cả trên mã, nếu chúng ta loại bỏ các cuộc gọi đến Sample.doIt
và tải nó trong iex
, và sau đó gọi Sample.doIt
hoạt động tốt.
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)>
Nếu tôi cố gắng require Sample
trong hồ sơ của tôi ở trên, như dưới đây
defmodule Sample
... rest of stuff as shown above ...
end
require Sample
Sample.doFunc "Hello World via Function"
Sample.doIt "Hello World from Macro!"
tôi nhận được lỗi
** (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
Ở đây, bạn đã định nghĩa một hàm 'run' trong một mô-đun khác để sử dụng' Sample.doIt' - đây là cách duy nhất để sử dụng macro - gọi nó qua một hàm khác được đặt trong Mô-đun –
. là một hạn chế của trình biên dịch. Khi lỗi nói - bạn không thể sử dụng Macro từ mô-đun trong cùng một ngữ cảnh nơi mô-đun được xác định. Tôi đoán nó đã làm với cách trình biên dịch đơn đặt hàng những thứ để biên dịch. –
Vâng, chính xác. Các macro được mở rộng tại thời gian biên dịch vì vậy khi chúng tôi phân tích cú pháp 'defmodule Foo' theo sau là' Foo.some_macro', chúng tôi vẫn chưa biên dịch 'Foo', vì vậy chúng tôi không biết cách mở rộng macro. –