什么时候应该在 .exs 文件中使用 defmodule
When we should use defmodule in .exs file
我尝试创建一个没有 config.exs
的混合项目,所以我创建了文件。
我从 phoenix 项目中推荐了 config.exs
。
我看到 config.exs
没有模块定义。我尝试在 .ex
文件中声明一个独立函数,它按预期引发了错误
** (ArgumentError) cannot invoke def/2 outside module
然后我假设 .exs
可以不写 defmodule
然后我看到 mix.exs
它有模块定义。为什么会这样?
我的问题是为什么在没有模块定义的情况下保留 config.exs
而在有定义的情况下保留 mix.exs
?
我们什么时候应该在 .exs
中使用 defmodule,什么时候不应该?
如果您查看 mix.exs
文件,您会注意到:
use Mix.Project
现在这个 file 包含:
@doc false
defmacro __using__(_) do
quote do
@after_compile Mix.Project
end
end
# Invoked after each Mix.Project is compiled.
@doc false
def __after_compile__(env, _binary) do
push(env.module, env.file)
end
@after_compile
是在 elixir/kernel.ex 中定义的宏,即使它的形式很奇怪,它是由 __using__
从 mix.exs
调用的。由于您不能在模块外调用宏,因此您需要在 mix.exs
文件中包含一个模块。
为了更清楚地说明这一点,让我们尝试删除 mix.exs
中的模块和 运行 项目:
* (ArgumentError) cannot invoke @/1 outside module
(elixir) lib/kernel.ex:5230: Kernel.assert_module_scope/3
(elixir) expanding macro: Kernel.@/1
mix.exs:2: (file)
(mix) expanding macro: Mix.Project.__using__/1
mix.exs:2: (file)
(elixir) expanding macro: Kernel.use/1
mix.exs:2: (file)
所以你的问题的答案是钩子 @after_compile
不能在没有模块的情况下调用,因为钩子本身就是宏。该钩子很可能用于在所有文件编译完成后自动加载项目。
PS: push/3
函数调用了一个有趣的模块函数:
Mix.ProjectStack.push(atom, config, file)
如果你查看 ProjectStack module you can observe that it is a state machine based on Agent 的来源。所以基本上所有的mix项目都压入栈中,可以检查是否重名。
我尝试创建一个没有 config.exs
的混合项目,所以我创建了文件。
我从 phoenix 项目中推荐了 config.exs
。
我看到 config.exs
没有模块定义。我尝试在 .ex
文件中声明一个独立函数,它按预期引发了错误
** (ArgumentError) cannot invoke def/2 outside module
然后我假设 .exs
可以不写 defmodule
然后我看到 mix.exs
它有模块定义。为什么会这样?
我的问题是为什么在没有模块定义的情况下保留 config.exs
而在有定义的情况下保留 mix.exs
?
我们什么时候应该在 .exs
中使用 defmodule,什么时候不应该?
如果您查看 mix.exs
文件,您会注意到:
use Mix.Project
现在这个 file 包含:
@doc false
defmacro __using__(_) do
quote do
@after_compile Mix.Project
end
end
# Invoked after each Mix.Project is compiled.
@doc false
def __after_compile__(env, _binary) do
push(env.module, env.file)
end
@after_compile
是在 elixir/kernel.ex 中定义的宏,即使它的形式很奇怪,它是由 __using__
从 mix.exs
调用的。由于您不能在模块外调用宏,因此您需要在 mix.exs
文件中包含一个模块。
为了更清楚地说明这一点,让我们尝试删除 mix.exs
中的模块和 运行 项目:
* (ArgumentError) cannot invoke @/1 outside module
(elixir) lib/kernel.ex:5230: Kernel.assert_module_scope/3
(elixir) expanding macro: Kernel.@/1
mix.exs:2: (file)
(mix) expanding macro: Mix.Project.__using__/1
mix.exs:2: (file)
(elixir) expanding macro: Kernel.use/1
mix.exs:2: (file)
所以你的问题的答案是钩子 @after_compile
不能在没有模块的情况下调用,因为钩子本身就是宏。该钩子很可能用于在所有文件编译完成后自动加载项目。
PS: push/3
函数调用了一个有趣的模块函数:
Mix.ProjectStack.push(atom, config, file)
如果你查看 ProjectStack module you can observe that it is a state machine based on Agent 的来源。所以基本上所有的mix项目都压入栈中,可以检查是否重名。