On m'a appris à déclarer mes variables d'instance avec def initialize
. J'ai eu l'impression que je pourrais déclarer des variables d'instance uniquement dans mes méthodes initialize
.
Néanmoins, j'ai déclaré une variable d'instance @foo
en dehors de mon initialize
, et l'a fait fonctionner comme je l'avais prévu:
class FooBar def initialize(bar) @bar = bar end def foo_as_instance_var @foo = @bar.split(' ') @foo end end x = "something wicked this way comes" y = FooBar.new(x) puts y.foo_as_instance_var
Pourquoi suis-je capable de déclarer une variable d'instance en dehors de la méthode initialize
? Puisque je peux déclarer des variables d'instance dans n'importe quelle méthode, y a-t-il une règle de bonnes pratiques à suivre, concernant où déclarer les variables d'instance (c'est-à-dire, les déclarer dans initialize
) ou cela n'a-t-il pas d'importance? >
3 Réponses :
On m'a appris à déclarer mes variables d'instance avec def initialize
Puisque
initialize
est le premier appel de méthode d'instance dans le cycle de vie d'un objet, vous déclarez généralement vos variables d'instance juste là afin de garantir des variables correctement initialisées. C'est aussi le premier endroit où je m'attendrais à ce que les variables d'instance soient définies lors de la lecture du code.J'ai eu l'impression que je ne pouvais déclarer des variables d'instance que dans mes méthodes d'initialisation.
Il n'y a pas de telle restriction. Vous pouvez déclarer une variable d'instance n'importe où dans votre instance.
Une utilisation courante est la mémorisation a >:
class FooController < ApplicationController def index @foos = Foo.all end endLors du premier appel, cela évaluerait
opération_chère
et attribuerait le résultat à@foo
. Lors des appels suivants,@foo
est renvoyé.Un autre exemple populaire est Rails qui utilise des variables d'instance pour transmettre les données du contrôleur à sa vue:
class FooBar def foo @foo ||= expensive_operation end endExiste-t-il une règle de bonnes pratiques que je devrais suivre pour savoir où déclarer les variables d'instance?
Cela dépend de leur objectif (voir les exemples ci-dessus). En règle générale, déclarez-les de manière à éviter les variables non définies (erreurs
nil
) et structurez votre code pour qu'il soit facile à lire / suivre.
Juste pour ajouter à l'excellente réponse de Stefan
On m'a appris à déclarer mes variables d'instance avec
def initialize
Une erreur courante que font les débutants de ruby est quelque chose comme ceci:
class Person @name = "John" def introduce puts "Hi, my name is #{@name}" end end
Et puis ils se demandent pourquoi leurs noms ne sont pas imprimés. Pour que cela fonctionne, on peut définir la variable @name
dans l'initialiseur, comme le dit l'instruction.
Commençons par le plus gros abus de langage - dans Ruby, il n'y a pas d'étape distincte pour déclarer les variables - Les variables sont déclarées lorsque vous les définissez.
Quelle est la différence? Regardez Java par exemple:
class Book def initialize(title, author) @title = title self.author = author # calls the setter. end # A factory method def create_from_csv(filename) # ... end # A very contrived setter def author=(author) @author = "#{author.forename.upcase}. #{author.surname}" end # a mutator def out_of_print! @out_of_print = true @last_printed = Date.today end end
Nous devons déclarer toutes les variables d'instance avant de les définir dans l'initialiseur (Bicycle). Le même code dans Ruby lit:
irb(main):003:0> @not_set => nil
Il n'y a pas de déclaration - seulement une affectation. Ruby vous permettra même d'accéder à des variables d'instance qui n'ont pas été définies sans erreur.
class Bicycle def initialize(cadence, speed, gear) @cadence = cadence @speed = speed @gear = gear end end
Vous ne pouvez pas faire cela (généralement) dans les langues où des variables doivent être définies *.
On m'a appris à déclarer mes variables d'instance avec def initialiser. J'ai eu l'impression que je pourrais déclarer variables d'instance uniquement dans mes méthodes d'initialisation.
Nonsense. Vous pouvez attribuer des variables d'instance n'importe où. Cela se fait généralement dans tout, des setters et mutators (méthodes qui modifient un objet) aux méthodes d'usine (méthodes de classe qui retournent une instance) ou partout où vous modifiez l'état d'un objet.
public class Bicycle { private int cadence; private int gear; private int speed; public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } }
* enfin à moins que vous ne parliez de Javascript qui est un flocon de neige très spécial.
"accéder aux variables d'instance qui n'ont pas été définies sans erreur" - il y aura cependant un avertissement (si activé).
Ça n'a pas d'importance. Faites ce qui a du sens. Vous avez eu une mauvaise impression si vous pensez que cela ne devrait se produire que lors de l'initialisation. Lisez ceci pour plus d'informations sur l'utilisation des variables d'instance en dehors de l'initialisation.
@anothermh j'étais. Et la question persistait définitivement au fond de ma tête ...
Pour pouvoir accéder à toutes les méthodes d'instance, c'est tout l'intérêt des variables d'instance.
@anothermh lol, j'ai littéralement oublié ou manqué
attr_accessor
. Merci!C'est une belle convention, mais juste ça. Vous pouvez en fait déclarer des variables d'instance de n'importe où en utilisant
instance_variable_set
(mais je ne vous conseillerais pas de le faire sauf si vous le devez pour la métaprogrammation)@maxpleaner pour la programmation dynamique en fait, ce qui n'est pas obligatoire meta :)
Lecture obligatoire pour quiconque envisage d'utiliser
instance_variable_set
.Si vous étiez uniquement autorisé à affecter des variables d'instance à l'intérieur de
initialize
, vous ne pourriez jamais, jamais les changer, sauf en appelant à nouveauinitialize
. Qui t'as dit ça? De plus,initialize
n'est qu'une méthode comme toute autre méthode, donc si vous n'étiez pas autorisé à attribuer des variables d'instance dans les méthodes, vous ne pouviez pas les attribuer dansinitialize
Soit. Le fait que vous puissiez les attribuer dansinitialize
prouve déjà que vous pouvez les assigner dans des méthodes, carinitialize
est une méthode. Toute cette déclaration n'a aucun sens.