web-dev-qa-db-fra.com

Différence entre les variables de classe et les variables d'instance de classe?

Quelqu'un peut-il me parler de la différence entre les variables de classe et les variables d'instance de classe?

89
cmd

Une variable de classe (@@) est partagée entre la classe et tous ses descendants. Une variable d'instance de classe (@) n'est pas partagée par les descendants de la classe.


Variable de classe (@@)

Ayons une classe Foo avec une variable de classe @@i et des accesseurs pour lire et écrire @@i:

class Foo

  @@i = 1

  def self.i
    @@i
  end

  def self.i=(value)
    @@i = value
  end

end

Et une classe dérivée:

class Bar < Foo
end

Nous voyons que Foo et Bar ont la même valeur pour @@i:

p Foo.i    # => 1
p Bar.i    # => 1

Et changer @@i en un le change dans les deux cas:

Bar.i = 2
p Foo.i    # => 2
p Bar.i    # => 2

Variable d'instance de classe (@)

Faisons une classe simple avec une variable d'instance de classe @i et des accesseurs pour lire et écrire @i:

class Foo

  @i = 1

  def self.i
    @i
  end

  def self.i=(value)
    @i = value
  end

end

Et une classe dérivée:

class Bar < Foo
end

Nous voyons que bien que Bar hérite des accesseurs pour @i, il n’hérite pas @i lui-même:

p Foo.i    # => 1
p Bar.i    # => nil

Nous pouvons définir le @i de Bar sans affecter le @i de Foo:

Bar.i = 2
p Foo.i    # => 1
p Bar.i    # => 2
147
Wayne Conrad

Vous devez d’abord comprendre que les classes sont aussi des instances - des instances de la classe Class.

Une fois que vous avez compris cela, vous pouvez comprendre qu’une classe peut avoir des variables d’instance qui lui sont associées tout comme un objet normal (lu: non-classe).

Hello = Class.new

# setting an instance variable on the Hello class
Hello.instance_variable_set(:@var, "good morning!")

# getting an instance variable on the Hello class
Hello.instance_variable_get(:@var) #=> "good morning!"

Notez qu'une variable d'instance sur Hello est complètement indépendante et distincte d'une variable d'instance sur un instance de Hello

hello = Hello.new

# setting an instance variable on an instance of Hello
hello.instance_variable_set(:@var, :"bad evening!")

# getting an instance variable on an instance of Hello
hello.instance_variable_get(:@var) #=> "bad evening!")

# see that it's distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"

Une variable class est en revanche une sorte de combinaison des deux éléments ci-dessus, car elle est accessible sur Hello et ses instances, ainsi que sur les sous-classes de Hello et leurs instances:

HelloChild = Class.new(Hello)
Hello.class_variable_set(:@@class_var, "strange day!")
hello = Hello.new
hello_child = HelloChild.new

Hello.class_variable_get(:@@class_var) #=> "strange day!"
HelloChild.class_variable_get(:@@class_var) #=> "strange day!"
hello.singleton_class.class_variable_get(:@@class_var) #=> "strange day!"
hello_child.singleton_class.class_variable_get(:@@class_Var) #=> "strange day!"

Beaucoup de gens disent d'éviter class variables en raison du comportement étrange décrit ci-dessus et recommandent plutôt d'utiliser class instance variables.

68
horseyguy

Aussi je veux ajouter que vous pouvez avoir accès à la variable de classe (@@) à partir de n'importe quelle instance de la classe

class Foo
  def set_name
    @@name = 'Nik'
  end

  def get_name
    @@name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => Nik

Mais vous ne pouvez pas faire la même chose pour la variable d'instance de la classe (@)

class Foo
  def set_name
    @name = 'Nik'
  end

  def get_name
    @name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => nil
0
Evan Ross