J'ai ce module en élixir avec un attribut:
defmodule MyAwesomeModule do
@awesome_number 7
# other stuff...
end
Je ne parviens pas à accéder à @awesome_number
en dehors du module. J'ai essayé d'utiliser Module.get_attribute/2
, mais elle renvoie cette erreur:
iex(79)> Module.get_attribute(MyAwesomeModule, :awesome_number)
** (ArgumentError) could not call get_attribute on module MyAwesomeModule because it was already compiled
(elixir) lib/module.ex:1101: Module.assert_not_compiled!/2
(elixir) lib/module.ex:1016: Module.get_attribute/3
Donc en ce moment, j'encapsule l'attribut module dans une méthode pour y accéder, mais cela n'a pas vraiment de sens pour moi. Je pourrais simplement utiliser la méthode et arrêter d'utiliser l'attribut tous ensemble:
defmodule MyAwesomeModule do
@awesome_number 7
def awesome_number, do: @awesome_number
# other stuff...
end
Donc ma question est, y a-t-il une meilleure façon/appropriée de faire cela?
AFAIK il n'y a aucun moyen d'accéder aux attributs du module en dehors du module donné. Définir une fonction pour exposer l'attribut du module est la voie à suivre, exactement ce que vous faites déjà.
Il pourrait toujours y avoir une bonne raison de conserver l'attribut de module, au lieu d'utiliser simplement la fonction sans l'attribut de module. Ça dépend du contexte. Gardez à l'esprit que la valeur stockée dans les attributs du module est calculée au moment de la compilation. Cela étant dit, vous pouvez avoir différentes raisons pour utiliser ou pour ne pas utiliser l'attribut du module. Regardons les exemples suivants:
Si la awesome_number
doivent être générés aléatoirement à chaque fois qu'on y accède, il suffit d'aller avec une fonction.
Si la awesome_number
doit être calculé (longtemps) et il n'a pas besoin de changer sa valeur, alors aller avec l'attribut + fonction du module pour l'exposer, est la voie à suivre.
Modifier:
Il y a plus à moduler les attributs de ce que j'ai dit plus tôt. Ils remplissent mieux que de simples fonctions. Voici un exemple et une citation des documents sur les élixirs:
defmodule MyServer do
@my_data 14
def first_data, do: @my_data
@my_data 13
def second_data, do: @my_data
end
MyServer.first_data #=> 14
MyServer.second_data #=> 13
Notez que la lecture d'un attribut à l'intérieur d'une fonction prend un instantané de sa valeur actuelle. En d'autres termes, la valeur est lue au moment de la compilation et non au moment de l'exécution. Comme nous allons le voir, cela rend les attributs utiles pour être utilisés comme stockage lors de la compilation du module.
Les utiliser avec Module.register_attribute/3
( https://hexdocs.pm/elixir/Module.html#register_attribute/ ) et surtout avec le accumulate: true
option, les rend utiles de plusieurs façons.
Ce que je veux dire, c'est qu'ils peuvent être plus utiles que d'être simplement utilisés comme une constante.
Il existe un moyen de "tricher" en utilisant use
et des macros. Regardez cet exemple .
Par exemple, supposons que vous définissiez un module comme:
defmodule AwesomeLibrary do
defmacro __using__(_) do
quote do
def print(s), do: IO.puts(s)
end
end
end
Ensuite, dans certains modules, vous pouvez utiliser le mot clé use
de cette manière.
defmodule TestLibrary do
use AwesomeLibrary
end
L'effet est que tout ce qui est défini dans le bloc __using__
Est copié dans le nouveau module au moment de la compilation. Donc, dans ce cas, vous pouvez utiliser TestLibrary.print
Même si print
est défini dans un autre module.
Ceci est également utilisé pour copier des constantes. À titre d'exemple, vous pouvez consulter la bibliothèque TimeX. Il utilise n module dédié aux constantes qui est importé chaque fois que cela est nécessaire.
Cela me semble la meilleure façon de partager des définitions de constantes autour d'une grande base de code.