简体   繁体   中英

What does “@” do in Elixir?

I have been looking through some coding solutions and they show the "@" symbol; however, I can't really seem to figure out what that symbol does by looking through documentation.

What does the @ symbol do in Elixir, and why is it important?

Here is an example:

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

The @ symbol in Elixir denotes module attributes , which are useful compile-time settings. You often see them in places where you might put class constants in an OO language.

However, module attributes are more subtle than what you might find in an OO language. Here are some important takeaways:

  1. They do not use the = to assign a value (as you might be in the habit of doing if you are used to defining class constants in OO-land). The syntax is more like function input where the optional parentheses are dropped.

  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
  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

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

It's the syntax for a 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.

Attributes are read by the compiler at compile-time, so they cannot be accessed or changed at runtime. At runtime, they will have been replaced with whatever was evaluated by the compiler.

In your case, this function:

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

Is effectively compiled to this:

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

@spec is used to define typespecs , @doc is for documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM