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

And*_*man 4 syntax 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
Run Code Online (Sandbox Code Playgroud)

Ada*_*hip 5

这是模块属性的语法:

Elixir 中的模块属性有三个用途:

  1. 它们用于注释模块,通常包含用户或虚拟机使用的信息。
  2. 它们作为常量工作。
  3. 它们作为编译期间使用的临时模块存储。

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

在你的情况下,这个函数:

defp get_rna_for_dna(dna_nucleotide) do
  @dna_nucleotide_to_rna_nucleotide_map[dna_nucleotide]
end
Run Code Online (Sandbox Code Playgroud)

有效地编译为:

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

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


Eve*_*ett 5

Elixir 中的符号@表示模块属性,这是有用的编译时设置。您经常会在 OO 语言中放置类常量的地方看到它们。

然而,模块属性比 OO 语言中的属性更加微妙。以下是一些重要的要点:

  1. 它们不使用=赋值(如果您习惯在 OO 领域定义类常量,您可能会习惯这样做)。语法更像是function input删除可选括号的地方。

  2. Module attributes can be redefined multiple times throughout the module. You'll see this frequently with @doc attributes that annotate the function that follows it, with @spec which annotates the function input/output, or inside tests with @tag to change the inputs to the test that follows it. This can offer a useful way to put big values out of the way of the function logic to improve readability.

  3. Module attributes can be accumulated. Normally, each instance of an attribute reassigns its value, but if you set accumulate: true when you register the attribute, then subsequent definitions will accumulate so that reading the attribute will return all the accumulated values. From the doc page:

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
Run Code Online (Sandbox Code Playgroud)
  1. Module attributes are evaluated at compile-time. Because they can raise visibility on important module-wide values, you might be tempted to do something like stash an ENV value:
defmodule Trouble do
  @my_value System.fetch_env("BOOM") # <-- don't do this!
end
Run Code Online (Sandbox Code Playgroud)

More recent versions of Elixir will show warnings if you attempt to do this (and some values, e.g. captured functions, will raise an error), so as a general rule of thumb, it's best to keep the module attributes simple and static.