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


Elixir Code用法及代码示例


Elixir语言中 Code 相关用法介绍如下。

用于管理代码编译、代码评估和代码加载的实用程序。

该模块补充了 Erlang 的:code 模块以添加特定于 Elixir 的行为。这个模块中的几乎所有函数都对 Elixir 的行为产生了全局副作用。

处理文件

该模块包含三个用于编译和评估文件的函数。以下是它们及其行为的摘要:

  • require_file/2 - 编译文件并跟踪其名称。如果以前需要该文件,它不会再次编译该文件。

  • compile_file/2 - 编译文件而不跟踪其名称。多次调用时多次编译文件。

  • eval_file/2 - 评估文件内容而不跟踪其名称。它返回文件中最后一个表达式的结果,而不是其中定义的模块。评估文件不会触发下一节中说明的编译跟踪器。

简而言之,当您要跟踪系统处理的文件时,必须使用第一个,以避免多次编译同一个文件。这在脚本中很常见。

compile_file/2 必须在您对文件中定义的模块感兴趣时使用,无需跟踪。当您对评估文件的结果而不是它定义的模块感兴趣时,应该使用 eval_file/2

上述函数适用于 Elixir 源代码。如果您想使用编译为字节码的模块,这些模块具有 .beam 扩展名,通常位于 Mix 项目的 _build 目录下,请参阅 Erlang 的 :code 模块中的函数。

Erlang VM 上的代码加载

Erlang 有两种加载代码的模式:交互式和嵌入式。

默认情况下,Erlang VM 以交互模式运行,模块根据需要加载。在嵌入式模式下,情况正好相反,因为所有模块都需要预先或显式加载。

您可以使用 ensure_loaded/1 (以及 ensure_loaded?/1 ensure_loaded!/1 )在使用模块之前检查模块是否已加载并采取行动。

ensure_compiled/1 ensure_compiled!/1

Elixir 还包括 ensure_compiled/1 ensure_compiled!/1 函数,它们是 ensure_loaded/1 的超集。

由于 Elixir 的编译是并行进行的,在某些情况下,您可能需要使用尚未编译的模块,因此甚至无法加载它。

调用时, ensure_compiled/1 ensure_compiled!/1 会停止调用者的编译,直到模块可用。请注意 ensure_compiled/1 ensure_compiled!/1 之间的区别很重要:如果您使用的是 ensure_compiled!/1 ,则表示您向编译器表明只有在所述模块可用时才能继续。

如果您正在使用 Code.ensure_compiled/1 ,则意味着您可以在没有模块的情况下继续,因此 Elixir 可能会在模块尚不可用的情况下返回 {:error, :unavailable}(但稍后可能可用)。

由于这些原因,开发人员通常必须使用 Code.ensure_compiled!/1 。特别是,不要这样做:

case Code.ensure_compiled(module) do
  {:module, _} -> module
  {:error, _} -> raise ...
end

最后,请注意您只需要 ensure_compiled!/1 来检查在同一项目中定义的模块。它不适用于依赖项中的模块,因为依赖项总是预先编译的。

在大多数情况下, ensure_loaded/1 就足够了。 ensure_compiled!/1 必须在极少数情况下使用,通常涉及需要调用模块以获取回调信息的宏。使用 ensure_compiled/1 的可能性更小。

编译跟踪器

Elixir 支持编译跟踪器,它允许模块在编译文件时观察 Elixir 编译器处理的结构。跟踪器是实现trace/2 函数的模块。该函数接收事件名称作为第一个参数和 Macro.Env 作为第二个参数,它必须返回 :ok 。跟踪器尽可能同步地做尽可能少的工作并将大部分工作分派给单独的进程是非常重要的。缓慢的跟踪器会减慢编译速度。

您可以通过 put_compiler_option/2 配置跟踪器列表。跟踪器可以使用以下事件:

  • :start -(从 v1.11.0 开始)在编译器开始跟踪新的词法上下文(例如新文件)时调用。请记住,编译器并行运行,因此多个文件可能会调用 :start 并同时运行。宏环境的lexical_tracker 的值,尽管是不透明的,但可用于唯一标识环境。

  • :stop -(从 v1.11.0 开始)在编译器停止跟踪新的词法上下文(例如新文件)时调用。

  • {:import, meta, module, opts} - 每当导入 module 时跟踪。 meta 是导入 AST 元数据,opts 是导入选项。

  • {:imported_function, meta, module, name, arity}{:imported_macro, meta, module, name, arity} - 每当调用导入的函数或宏时进行跟踪。 meta 是调用 AST 元数据,module 是导入的模块,然后是导入的函数/宏的 namearity

  • {:alias, meta, alias, as, opts} - 每当 alias 别名为 as 时跟踪。 meta 是别名 AST 元数据,opts 是别名选项。

  • {:alias_expansion, meta, as, alias} 跟踪先前定义的 alias 的别名扩展,即当用户写入扩展为 aliasas 时。 meta 是别名扩展 AST 元数据。

  • {:alias_reference, meta, module} - 只要代码中有别名,即用户在代码中写入 MyModule.Foo.Bar 时进行跟踪,无论它是否被扩展。

  • {:require, meta, module, opts} - 每当需要 module 时进行跟踪。 meta 是要求 AST 元数据,opts 是要求选项。

  • {:struct_expansion, meta, module, keys} - 每当 module 的结构展开时跟踪。 meta 是结构 AST 元数据,keys 是扩展使用的键

  • {:remote_function, meta, module, name, arity}{:remote_macro, meta, module, name, arity} - 每当引用远程函数或宏时进行跟踪。 meta 是调用 AST 元数据,module 是调用的模块,然后是 namearity

  • {:local_function, meta, name, arity}{:local_macro, meta, name, arity} - 每当引用本地函数或宏时跟踪。 meta 是调用 AST 元数据,后跟 namearity

  • {:compile_env, app, path, return} - 每当调用 Application.compile_env/3 Application.compile_env!/2 时跟踪。 app 是原子,path 是要在应用程序环境中遍历的键列表,而 return{:ok, value}:error

  • {:on_module, bytecode, :none} -(自 v1.11.0 起)在定义模块时跟踪。这等效于 @after_compile 回调,并在给定模块中的任何 @after_compile 之后调用。第三个元素目前是:none,但将来可能会提供更多元数据。最好暂时忽略它。

:tracers 编译器选项可以与:parser_options 编译器选项结合使用,以丰富上述跟踪事件的元数据。

将来可能随时添加新事件,因此建议trace/2 函数具有"catch-all" 子句。

下面是一个打印所有远程函数调用的示例跟踪器:

defmodule MyTracer do
  def trace({:remote_function, _meta, module, name, arity}, env) do
    IO.puts "#{env.file}:#{env.line} #{inspect(module)}.#{name}/#{arity}"
    :ok
  end

  def trace(_event, _env) do
    :ok
  end
end

相关用法


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