我正在从https://elixirschool.com/en/lessons/basics/control-structures/学习控制结构 我注意到它提到了
如果以前有if / 2,您会遇到的机会;如果您使用过Ruby,则除非熟悉/ 2。在Elixir中,它们的工作方式大致相同,但它们被定义为宏,而不是语言构造。您可以在内核模块中找到它们的实现。
那么Elixir中的语言构造和宏之间有什么区别?什么时候需要编写宏?
答案 0 :(得分:3)
宏是一种对编程语言进行编程的方法。简而言之,宏是一种生成程序代码的方法,而不是始终自己编写代码。
另一方面,一种语言构造(有时称为“特殊形式”)是长生不老药本身的核心。过于简单的做法是if
的实现不是在Elixir中完成的,而是在实现Elixir的语言中完成的。
假设您要使用提到的unless
。
编辑:unless
在Elixir中可用。但是让我们假设其余的不是。
在Elixir中,没有unless
的语言版本。 Jose Valim没有实现它。但是,您始终可以编写具有相同语义的内容:否定的if
。
我们想 拥有这个,但我们不:
unless sun_shines() do
open_umbrella()
end
但是我们只有一个if
和一个not
,所以我们可以这样写:
if not sun_shines() do
open_umbrella()
end
第二,宏是一种特殊的函数,但是它的参数是代码,执行宏的结果也是代码。假设我们有unless
宏,它接受一个条件(即sun_shines()
)和一个主体(即open_umbrella()
),并返回if not sun_shines(), do: open_umbrella()
。因此,宏是可以在“无效代码”级别工作并生成“无效代码”的功能。
您可能会认为这太愚蠢了,无法为其编写宏。确实如此。但是这些类型的问题比您想象的要经常发生,因此宏是解决该问题的好方法。这只是编程您的编程语言的一种方法。
Aleksei Matiushkin提供了unless
宏的示例实现:
defmodule MyMacros do
defmacro unless(ast, do: block) do
quote do
if not unquote(ast) do
unquote(block)
end
end
end
end
在这里您可以清楚地看到给它一个AST(抽象语法树),它将把它转换为另一个AST(quote
),并将其注入到调用宏的位置。请注意,这都是在编译时发生的。您的程序目前尚未执行!
例如,假设您具有上述模块,这是您的程序:
defmodule MyProgram do
def my_function(x) do
unless sun_shining() do
open_umbrella()
end
end
end
在编译之后和执行之前,您的程序将如下所示:
defmodule MyProgram do
def my_function(x) do
if not sun_shining() do
open_umbrella()
end
end
end
此阶段称为宏扩展阶段。
另外,您可以在这里找到分别在Elixir和ExUnit中使用的两个实际宏。
注意:我一直在为该答案添加越来越多的信息。答案实际上值得一整本书,而 Chris McCord 的Metaprogramming Elixir是最好的一本书。