4
votes

Déclarer une variable d'instance en dehors de la méthode `initialize`

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? >


8 commentaires

Ç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 à nouveau initialize . 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 dans initialize Soit. Le fait que vous puissiez les attribuer dans initialize prouve déjà que vous pouvez les assigner dans des méthodes, car initialize est une méthode. Toute cette déclaration n'a aucun sens.


3 Réponses :


6
votes

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
end

Lors 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
end

Existe-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.


0 commentaires

5
votes

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.


0 commentaires

2
votes

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;
    }
}


2 commentaires

* 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é).