是否在if块中定义的函数在编译时取出?如果在编译时运行,将顶层吗?

时间:2019-07-18 15:39:58

标签: elixir

出于安全原因,我拥有仅在开发环境中可用的功能。如果我做这样的事情:

if Mix.env() == :dev do
    def some_func() do
        do_sensitive_stuff()
    end
end

编译项目时,if块中的代码是否不会被编译?更一般而言,我可以像这样在编译时运行代码吗?还是我需要像宏这样的东西?

1 个答案:

答案 0 :(得分:1)

Elixir实际上是在Erlang VM之上的一种DSL。域非常广泛,但仍然如此。 Elixir中的几乎所有东西都是

defdefmodule,甚至defmacro本身就是indeed a macro

编译器的工作原理没有魔力。在第一阶段,它将遍历源代码并将所有内容转换为AST。当它看到宏时,将其展开(宏返回AST),并将返回的AST注入到恰好出现宏的位置。

在文件的顶层,defmoduledefmoduledef等内可能都有一个代码。所有内容都将被扩展,直到无法进一步扩展为止。

当编译器看到if时,它会扩展if宏,但仍然没有魔术。

现在您可能会想知道为什么在编译阶段之后还剩下一些“可运行”的东西。当编译器看到def或任何其他返回AST的宏时,它会存储该AST(然后该AST实际上会转换为BEAM文件。)

作为示例,您可以尝试以下代码:

defmodule Test do
  IO.puts("I am compiling")

  def run, do: IO.puts("I am running")
end

如果您尝试对其进行编译,则会看到以前的消息在编译阶段出现。后者只有在编译后显式调用Test.run/0时才会出现。