Ответ 1
Вы можете добавить имя переменной @
:
defmodule MyModule do
@my_favorite_number 13
end
Вот docs
В Ruby, если бы кто-то определял константы в классах, они определяли бы их, используя все кепки. Например:
class MyClass
MY_FAVORITE_NUMBER = 13
end
Как вы это делаете в Эликсире? И если такой эквивалент не существует, как вы обходите проблему магических чисел в Elixir?
Вы можете добавить имя переменной @
:
defmodule MyModule do
@my_favorite_number 13
end
Вот docs
Другой подход к определению констант - это тот, который я взял с файлами заголовков 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 , если вам интересно.
Как я уже сказал, я добавляю этот ответ в основном ради полноты.
Модули Elixir могут иметь связанные метаданные. Каждый элемент в метаданных называется атрибутом и имеет доступ к его имени. Вы определяете его внутри модуля с помощью @name value
. И доступен как @name
defmodule Example
@site 'StackOverflow' #defining attribute
def get_site do
@site #access attribute
end
end
Помните, что это работает только на верхнем уровне модуля, и вы не можете установить атрибут модуля внутри определения функции.
Может быть, вы определяете файл модуля констант и в нем вы можете определить макросы для этого так:
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
Я хотел добавить, как я начал делать константы, что похоже на ответ @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
файла констант, существует конфликт двусмысленности. Изменение их для функций, ограниченных в частном порядке, позволяет избежать этого конфликта. Поэтому каждый модуль имеет свою собственную "частную копию" той же константы.