当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Elixir Macro.expand_once用法及代码示例


Elixir语言中 Macro.expand_once 相关用法介绍如下。

用法:

expand_once(ast, env)

接收一个 AST 节点并展开一次。

展开以下内容:

如果表达式无法展开,则返回表达式本身。这个函数不遍历AST,只展开根节点。

expand_once/2 只执行一次扩展。勾选 expand/2 进行扩展,直到节点不能再扩展。

例子

在下面的示例中,我们有一个宏,它生成一个带有名为name_length 的函数的模块,该函数返回模块名称的长度。此函数的值将在编译时计算,而不是在运行时计算。

考虑下面的实现:

defmacro defmodule_with_length(name, do: block) do
  length = length(Atom.to_charlist(name))

  quote do
    defmodule unquote(name) do
      def name_length, do: unquote(length)
      unquote(block)
    end
  end
end

当像这样调用时:

defmodule_with_length My.Module do
  def other_function, do: ...
end

编译将失败,因为引用时的My.Module 不是原子,而是语法树,如下所示:

{:__aliases__, [], [:My, :Module]}

也就是说,我们需要将上面的别名节点扩展为一个原子,以便我们可以检索它的长度。扩展节点并不简单,因为我们还需要扩展调用者别名。例如:

alias MyHelpers, as: My

defmodule_with_length My.Module do
  def other_function, do: ...
end

最终的模块名称将是 MyHelpers.Module 而不是 My.Module 。使用 Macro.expand/2 时,会考虑此类别名。本地和远程宏也被扩展。我们可以重写上面的宏来使用这个函数:

defmacro defmodule_with_length(name, do: block) do
  expanded = Macro.expand(name, __CALLER__)
  length = length(Atom.to_charlist(expanded))

  quote do
    defmodule unquote(name) do
      def name_length, do: unquote(length)
      unquote(block)
    end
  end
end

相关用法


注:本文由纯净天空筛选整理自elixir-lang.org大神的英文原创作品 Macro.expand_once(ast, env)。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。