web-dev-qa-db-fra.com

Attributs du module d'accès en dehors du module

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?

19
Sheharyar

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.

21
ventsislaf

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.

11
Davide Aversa