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


Elixir Kernel.@expr用法及代码示例

Elixir语言中 Kernel.@expr 相关用法介绍如下。

用法:

@expr
(宏)

模块属性一元运算符。

读取和写入当前模块中的属性。

属性的典型示例是注释模块实现了 OTP 行为,例如 GenServer

defmodule MyServer do
  @behaviour GenServer
  # ... callbacks ...
end

默认情况下,Elixir 支持 Erlang 支持的所有模块属性,但也可以使用自定义属性:

defmodule MyServer do
  @my_data 13
  IO.inspect(@my_data)
  #=> 13
end

与 Erlang 不同,这些属性默认不存储在模块中,因为 Elixir 中通常使用自定义属性来存储在编译时可用的临时数据。可以使用 Module.register_attribute/3 将自定义属性配置为更接近 Erlang。

重要提示:库和框架应考虑使用下划线作为私有模块属性的前缀,例如@_my_data,以便代码完成工具不会在建议和提示中显示它们。

最后,注意属性也可以在函数内部读取:

defmodule MyServer do
  @my_data 11
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

MyServer.first_data()
#=> 11

MyServer.second_data()
#=> 13

需要注意的是,读取属性会获取其当前值的快照。换句话说,该值是在编译时读取的,而不是在运行时读取的。检查 Module 模块是否有其他函数来操作模块属性。

注意力!同一属性的多个引用

如上所述,每次读取模块属性时,都会对其当前值进行快照。因此,如果您在模块属性中存储较大的值(例如,在模块属性中嵌入外部文件),则应避免多次引用同一属性。例如,不要这样做:

@files %{
  example1: File.read!("lib/example1.data"),
  example2: File.read!("lib/example2.data")
}

def example1, do: @files[:example1]
def example2, do: @files[:example2]

在上文中,对@files 的每个引用都可能在end-up 中带有整个@files 模块属性的完整且单独的副本。相反,在私有函数中引用一次模块属性:

@files %{
  example1: File.read!("lib/example1.data"),
  example2: File.read!("lib/example2.data")
}

defp files(), do: @files
def example1, do: files()[:example1]
def example2, do: files()[:example2]

注意力!编译时依赖

请记住对其他模块的引用,即使在模块属性中,也会生成对所述模块的编译时依赖项。

例如,采用这种常见模式:

@values [:foo, :bar, :baz]

def handle_arg(arg) when arg in @values do
  ...
end

虽然上面没问题,但想象一下,如果您在模块属性中有实际的模块名称,如下所示:

@values [Foo, Bar, Baz]

def handle_arg(arg) when arg in @values do
  ...
end

上面的代码将定义对模块 FooBarBaz 的编译时依赖,如果它们中的任何一个发生变化,当前模块将不得不重新编译。在这种情况下,最好完全避免使用模块属性:

def handle_arg(arg) when arg in [Foo, Bar, Baz] do
  ...
end

相关用法


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