【问题标题】:Define another macro inside __using__在 __using__ 中定义另一个宏
【发布时间】:2018-10-31 02:47:25
【问题描述】:

我有一个名为 Interfaces 的模块:

defmodule Interfaces do
  defmacro __using__(module) do
    @module unquote(module) |> List.first |> elem(1)
    defmacro expose(name) do
      IO.inspect params, label: "Expanding macro with: "
      IO.inspect @module, label: "I need this !!"

      def unquote(name)() do
        IO.puts "The function has been created with exposed name"
      end
    end
  end
end

另一个名为 Interfaces.MyModule 的模块:

defmodule Interfaces.MyModule do
  use Interfaces, for: Something.DefinedElseWhere

  expose :plop
end

但在编译时我得到了

** (CompileError) lib/my_module.ex:6: undefined function expose/1

【问题讨论】:

  • 这是什么意思?你已经在一个宏里面了,为什么不直接定义一个常规函数呢?至于实际问题,我不知道这是否应该工作。
  • 我编辑了我的例子,所以你会明白这一点,它应该定义一个函数,其名称在 expose 参数中传递
  • 为什么不直接创建那个宏而不是通过__using__
  • 因为我需要use语句中传递的选项

标签: macros elixir


【解决方案1】:

我强烈建议您阅读 Elixir 官方网站上的Macros Guide。虽然您正在做的事情是可能的(使用quote),但根本不鼓励这样做。

宏应该很简单,如果需要,它们的功能应该在其他宏和方法中进一步分解。 一种方法是在您的宏中使用import 语句 来导入您需要在最终模块中公开的其他宏:

defmodule Interface do
  defmacro __using__(opts) do
    quote(bind_quoted: [opts: opts]) do
      import Interface

      @interface_module Keyword.get(opts, :for)
    end
  end

  defmacro expose(name) do
    quote do
      IO.inspect @interface_module, label: "I need this !!"

      def unquote(name)() do
        IO.puts "The function has been created with exposed name"
      end
    end
  end
end

现在您可以使用它了:

defmodule MyImplementation do
  use Interface, for: AnotherModule

  expose(:hello)
end

这是我的一个项目中的another example,关于如何使用辅助函数和其他宏分解大型宏的实现。

【讨论】:

  • 这就是我最终所做的。不想在接口模块中公开expose,但我可以忍受它。谢谢!
  • 您还可以专门调用import Interface, only: [expose: 1] 和/或使用expose 宏创建一个单独的未记录的Interface.Definition 模块并从那里导入。
  • 另一种确保用户首先调用use Interface的方法是使用Compile Callbacks
猜你喜欢
  • 2017-01-22
  • 2019-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 2019-12-17
  • 1970-01-01
  • 2017-08-13
相关资源
最近更新 更多