“@”在 Elixir 中有什么作用?

What does "@" do in Elixir?

我一直在查看一些编码解决方案,它们显示“@”符号;但是,我似乎无法通过查看文档来弄清楚该符号的作用。

@ 符号在 Elixir 中有什么作用,为什么它很重要?

这是一个例子:

defmodule RNATranscription do
  @dna_nucleotide_to_rna_nucleotide_map %{
    # `G` -> `C`
    71 => 67,

    # `C` -> `G`
    67 => 71,

    # `T` -> `A`
    84 => 65,

    # `A` -> `U`
    65 => 85
  }

  @doc """
  Transcribes a character list representing DNA nucleotides to RNA

  ## Examples

  iex> RNATranscription.to_rna('ACTG')
  'UGAC'
  """
  @spec to_rna([char]) :: [char]
  def to_rna(dna) do
    dna
    |> Enum.map(&get_rna_for_dna/1)
  end

  defp get_rna_for_dna(dna_nucleotide) do
    @dna_nucleotide_to_rna_nucleotide_map[dna_nucleotide]
  end
end

这是 module attribute:

的语法

Module attributes in Elixir serve three purposes:

  1. They serve to annotate the module, often with information to be used by the user or the VM.
  2. They work as constants.
  3. They work as a temporary module storage to be used during compilation.

编译器在编译时读取属性,因此无法在运行时访问或更改它们。在运行时,它们将被编译器评估的任何内容替换。

在你的例子中,这个函数:

defp get_rna_for_dna(dna_nucleotide) do
  @dna_nucleotide_to_rna_nucleotide_map[dna_nucleotide]
end

有效编译为:

defp get_rna_for_dna(dna_nucleotide) do
  %{
    71 => 67,
    67 => 71,
    84 => 65,
    65 => 85
  }[dna_nucleotide]
end

@spec用于定义typespecs@doc用于文档。

Elixir 中的@ 符号表示module attributes,这是有用的编译时设置。您经常在 OO 语言中可能放置 class 常量的地方看到它们。

但是,模块属性比您在 OO 语言中可能发现的更微妙。以下是一些重要的要点:

  1. 他们 而不是 使用 = 来赋值(如果您习惯于定义,您可能习惯这样做class 面向对象领域的常量)。语法更像 function input,其中删除了可选的括号。

  2. 模块属性可以在整个模块中多次重新定义。您会经常看到 @doc 属性注释其后的函数,@spec 注释函数 input/output,或者在内部测试中使用 @tag 更改输入到它后面的测试。这可以提供一种有用的方法来将大值放在函数逻辑之外以提高可读性。

  3. 模块属性可以累积。通常情况下,一个属性的每个实例都会重新赋值,但是如果你在注册属性的时候设置了accumulate: true,那么后面的定义会累积起来,这样读取属性就会returnall 累加值。来自文档页面:

defmodule MyModule do
  Module.register_attribute(__MODULE__, :custom_threshold_for_lib, accumulate: true)

  @custom_threshold_for_lib 10
  @custom_threshold_for_lib 20
  @custom_threshold_for_lib #=> [20, 10]
end
  1. 模块属性在编译时评估。因为它们可以提高对重要模块范围值的可见性,所以您可能会想做一些类似于隐藏 ENV 值的事情:
defmodule Trouble do
  @my_value System.fetch_env("BOOM") # <-- don't do this!
end

如果您尝试这样做,较新版本的 Elixir 将显示警告(并且某些值,例如捕获的函数,将引发错误),因此作为一般经验法则,最好保持模块属性简单和静态。