Подтвердить что ты не робот

Как вы определяете константы в модулях Elixir?

В Ruby, если бы кто-то определял константы в классах, они определяли бы их, используя все кепки. Например:

class MyClass
  MY_FAVORITE_NUMBER = 13
end

Как вы это делаете в Эликсире? И если такой эквивалент не существует, как вы обходите проблему магических чисел в Elixir?

4b9b3361

Ответ 1

Вы можете добавить имя переменной @:

defmodule MyModule do
  @my_favorite_number 13
end

Вот docs

Ответ 2

Другой подход к определению констант - это тот, который я взял с файлами заголовков wxErlang. То есть вы можете просто определить одну функцию линии, которая возвращает постоянное значение для вас. Например:

  def wxHORIZONTAL, do: 4
  def wxVERTICAL, do: 8
  def wxBOTH, do: (wxHORIZONTAL ||| wxVERTICAL)

и вот еще один пример из того же исходного кода:

 # From "defs.h": wxDirection
  def wxLEFT, do: 16
  def wxRIGHT, do: 32
  def wxUP, do: 64
  def wxDOWN, do: 128
  def wxTOP, do: wxUP
  def wxBOTTOM, do: wxDOWN
  def wxNORTH, do: wxUP
  def wxSOUTH, do: wxDOWN
  def wxWEST, do: wxLEFT
  def wxEAST, do: wxRIGHT
  def wxALL, do: (wxUP ||| wxDOWN ||| wxRIGHT ||| wxLEFT)

Как вы можете видеть, это немного упрощает определение константы в терминах другой константы. И когда мне нужны эти константы в другом модуле, все, что мне нужно сделать, это require WxConstants в верхней части модуля. Это облегчает определение константы в одном месте и использование ее в нескольких других - помогает много с DRY.

Кстати, вы можете увидеть здесь repo , если вам интересно.

Как я уже сказал, я добавляю этот ответ в основном ради полноты.

Ответ 3

Модули Elixir могут иметь связанные метаданные. Каждый элемент в метаданных называется атрибутом и имеет доступ к его имени. Вы определяете его внутри модуля с помощью @name value. И доступен как @name

defmodule Example
  @site 'StackOverflow' #defining attribute

  def get_site do
    @site #access attribute
  end 
end

Помните, что это работает только на верхнем уровне модуля, и вы не можете установить атрибут модуля внутри определения функции.

Ответ 4

Может быть, вы определяете файл модуля констант и в нем вы можете определить макросы для этого так:

defmodule MyApp.Constants do
  defmacro const_a do
    quote do: "A"
  end
end

Вы используете его, импортируя его в любой другой модуль

defmodule MyApp.ModuleA do
  import MyApp.Constants

  def get_const_a do
    const_a()
  end 
end

Преимущество также в том, что вы не берете на себя никакой стоимости во время выполнения, а также преимущество использования его в случае соответствия

case something do
  const_a() -> do_something
  _ -> do_something_else
end

Ответ 5

Я хотел добавить, как я начал делать константы, что похоже на ответ @Onorio Catenacci, но использует цитирование:

defmodule IbGib.Constants do

  @doc """
  Use this with `use IbGib.Constants, :ib_gib`
  """
  def ib_gib do
    quote do
      defp delim, do: "^"
      defp min_id_length, do: 1
      # etc...
    end
  end

  @doc """
  Use this with `use IbGib.Constants, :error_msgs`
  """
  def error_msgs do
    quote do
      defp emsg_invalid_relations do
        "Something about the rel8ns is invalid. :/"
      end
      # etc...
    end
  end

  @doc """
  When used, dispatch to the appropriate controller/view/etc.
  """
  defmacro __using__(which) when is_atom(which) do
    apply(__MODULE__, which, [])
  end
end

И затем вы используете его так, как в верхней части модуля, где вы хотите их использовать:

use IbGib.Constants, :ib_gib # < specifies only the ib_gib constants
use IbGib.Constants, :error_msgs

# ... then in some function
Logger.error emsg_invalid_relations

Я получил это с тем, как Phoenix импортирует/использует предложения с MyApp.Web. Я нигде не знаком с экспертом Elixir, но с помощью этого метода вы можете импортировать только те константы, которые вы хотите, и вам не нужно префикс их с помощью какого-либо пространства имен /scoping. Таким образом, вы можете легко выбирать и выбирать отдельные группы констант.

С прямыми функциями (я думаю) вам придется разбить их на несколько модулей, а затем импортировать модуль.

Я не знаю оптимизационных последствий этой функции vs direct module, но я думал, что это довольно аккуратно - особенно для практики между различными способами "импортировать" вещи в Elixir (import, use, alias, require очень сбивает с толку, поскольку новичок приходит с других языков, где это одиночный оператор using или import).

EDIT: я изменил константные объявления def на defp. Это происходит потому, что, когда несколько модулей import файла констант, существует конфликт двусмысленности. Изменение их для функций, ограниченных в частном порядке, позволяет избежать этого конфликта. Поэтому каждый модуль имеет свою собственную "частную копию" той же константы.