En Ruby, si l'on définissait des constantes dans les classes, elles les définiraient en utilisant toutes les majuscules. Par exemple:
class MyClass
MY_FAVORITE_NUMBER = 13
end
Comment faites-vous cela dans Elixir? Et si aucun équivalent n'existe, comment contourner le problème des nombres magiques dans Elixir?
Vous pouvez ajouter votre nom de variable avec @
:
defmodule MyModule do
@my_favorite_number 13
end
Voici les docs
Les modules Elixir peuvent avoir des métadonnées associées. Chaque élément des métadonnées est appelé un attribut et est accessible par son nom. Vous le définissez à l'intérieur d'un module en utilisant @name value
. Et est accessible en tant que @name
defmodule Example
@site 'StackOverflow' #defining attribute
def get_site do
@site #access attribute
end
end
N'oubliez pas que cela ne fonctionne qu'au niveau supérieur d'un module et que vous ne pouvez pas définir un attribut de module dans une définition de fonction.
Une autre approche pour définir les constantes est celle que j'ai adoptée avec les fichiers d'en-tête wxErlang. Autrement dit, vous pouvez simplement définir une fonction de ligne unique qui renvoie la valeur constante pour vous. Ainsi:
def wxHORIZONTAL, do: 4
def wxVERTICAL, do: 8
def wxBOTH, do: (wxHORIZONTAL ||| wxVERTICAL)
et voici un autre exemple du même code source:
# 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)
Comme vous pouvez le voir, il est un peu plus facile de définir une constante en termes d'une autre constante. Et quand je veux ces constantes dans un module différent, tout ce que je dois faire est de require WxConstants
en haut du module. Cela facilite beaucoup la définition d'une constante en un seul endroit et son utilisation dans plusieurs autres - cela aide beaucoup avec DRY.
Au fait, vous pouvez voir le repo ici si vous êtes curieux.
Comme je l'ai dit, j'ajoute cette réponse principalement par souci d'exhaustivité.
Peut-être que vous définissez un fichier de module de constantes et que vous pouvez y définir des macros comme ceci
defmodule MyApp.Constants do
defmacro const_a do
quote do: "A"
end
end
Vous l'utilisez en l'important dans n'importe quel autre module
defmodule MyApp.ModuleA do
import MyApp.Constants
def get_const_a do
const_a()
end
end
L'avantage est également que vous n'encourez aucun coût d'exécution ainsi que l'avantage de l'utiliser en cas de correspondance
case something do
const_a() -> do_something
_ -> do_something_else
end
En regardant autour de github, je vois que cela est utilisé, ce qui me plaît. Permet d'accéder à la constante à partir d'autres modules.
ModuleA
@my_constant 23
defmacro my_constant, do: @my_constant
ModuleB
Require ModuleA
@my_constant ModuleA.my_constant
Encore une fois une solution d'élixir simple et fascinante
Je voulais ajouter comment j'ai commencé à faire des constantes, ce qui est similaire à la réponse de @Onorio Catenacci, mais utilise des citations:
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
Et puis vous l'utilisez comme ceci en haut du module où vous voulez les consommer:
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
J'ai compris comment Phoenix importait/utilisait des clauses avec MyApp.Web. Je ne suis pas du tout près d'un expert Elixir, mais avec cette méthode, vous pouvez importer uniquement les constantes que vous souhaitez et vous n'avez pas besoin de les préfixer avec un espace de noms/portée. De cette façon, vous pouvez facilement sélectionner les groupes individuels de constantes.
Avec des fonctions simples, (je pense), vous devrez les diviser en plusieurs modules, puis importer le module.
Je ne connais pas les ramifications d'optimisation de ces fonctions vs module direct, mais je pensais que c'était assez soigné - en particulier pour la pratique entre les différentes façons d'importer des choses dans Elixir (import
, use
, alias
, require
est très déroutant en tant que débutant venant d'autres langues où il s'agit d'une seule instruction using
ou import
).
EDIT: J'ai changé les déclarations constantes def
en defp
. En effet, lorsque plusieurs modules import
le fichier de constantes, il y a un conflit d'ambiguïté. Le fait de les remplacer par des fonctions de portée privée évite ce conflit. Ainsi, chaque module possède sa propre "copie privée" de la même constante.