返回介绍

Macros( Macros)

发布于 2021-05-25 13:29:46 字数 1795 浏览 987 评论 0 收藏 0

宏是Elixir最先进和最强大的功能之一。 与任何语言的所有高级功能一样,应谨慎使用宏。 它们使得在编译时执行强大的代码转换成为可能。 我们现在将了解宏是什么以及如何简单地使用它们。

Quote

在我们开始讨论宏之前,让我们先来看看Elixir内部。 Elixir程序可以由其自己的数据结构表示。 Elixir程序的构建块是一个包含三个元素的元组。 例如,函数调用sum(1,2,3)在内部表示为 -

{:sum, [], [1, 2, 3]}

第一个元素是函数名称,第二个元素是包含元数据的关键字列表,第三个是参数列表。 如果您编写以下内容,可以将此作为iex shell中的输出 -

quote do: sum(1, 2, 3)

运算符也表示为这样的元组。 变量也使用这样的三元组来表示,除了最后一个元素是原子而不是列表。 当引用更复杂的表达式时,我们可以看到代码在这样的元组中表示,这些元组通常在类似于树的结构中彼此嵌套。 许多语言将此类表示称为Abstract Syntax Tree (AST) 。 Elixir称这些引用的表达式。

Unquote

现在我们可以检索代码的内部结构,我们如何修改它? 要注入新的代码或值,我们使用unquote 。 当我们取消引用表达式时,它将被评估并注入AST。 让我们考虑一个例子(在iex shell中)来理解这个概念 -

num = 25
quote do: sum(15, num)
quote do: sum(15, unquote(num))

运行上述程序时,会产生以下结果 -

{:sum, [], [15, {:num, [], Elixir}]}
{:sum, [], [15, 25]} 

在引用表达式的示例中,它没有自动将num替换为25.如果我们想要修改AST,则需要取消引用此变量。

Macros

所以现在我们熟悉quote和unquote,我们可以使用宏来探索Elixir中的元编程。

在最简单的术语中,宏是特殊函数,用于返回将插入到我们的应用程序代码中的带引号的表达式。 想象一下,宏被引用的表达式替换而不是像函数一样调用。 使用宏,我们拥有扩展Elixir并动态添加代码到应用程序所需的一切

除非作为宏,否则让我们实施。 我们将首先使用defmacro宏定义宏。 请记住,我们的宏需要返回一个带引号的表达式。

defmodule OurMacro do
   defmacro unless(expr, do: block) do
      quote do
         if !unquote(expr), do: unquote(block)
      end
   end
end
require OurMacro
OurMacro.unless true, do: IO.puts "True Expression"
OurMacro.unless false, do: IO.puts "False expression"

运行上述程序时,会产生以下结果 -

False expression 

这里发生的是我们的代码正在被unless宏返回的引用代码所取代。 我们没有引用该表达式来在当前上下文中对其进行求值,并且还没有引用do块来在其上下文中执行它。 这个例子向我们展示了在elixir中使用宏的元编程。

宏可用于更复杂的任务,但应谨慎使用。 这是因为元编程通常被认为是一种不好的做法,只应在必要时使用。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文