Quelqu'un peut-il me parler de la différence entre les variables de classe et les variables d'instance de classe?
Réponses:
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 ( @@
)
Prenons une classe Foo avec une variable de classe @@i
et des accesseurs pour la lecture et l'écriture @@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
On voit que Foo et Bar ont la même valeur pour @@i
:
p Foo.i # => 1
p Bar.i # => 1
Et changer @@i
dans un le change dans les deux:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
Variable d'instance de classe ( @
)
Créons une classe simple avec une variable d'instance de classe @i
et des accesseurs pour la lecture et l'écriture @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
On voit que bien que Bar hérite des accesseurs pour @i
, il n'hérite pas de @i
lui-même:
p Foo.i # => 1
p Bar.i # => nil
Nous pouvons définir Bar's @i
sans affecter les Foo @i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
Vous devez d'abord comprendre que les classes sont aussi des instances - des instances de la Class
classe.
Une fois que vous comprenez cela, vous pouvez comprendre qu'une classe peut être associée à des variables d'instance 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 une instance deHello
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 de classe, en revanche, est une sorte de combinaison des deux ci-dessus, car elle est accessible sur Hello
elle-même 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 qu'il faut éviter en class variables
raison du comportement étrange ci-dessus et recommandent d'utiliser à la class instance variables
place.
Je souhaite également ajouter que vous pouvez accéder à 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 de même pour la variable d'instance de 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
Foo.i
, mais comment pouvez-vous faire la même chose pour chaque instance de cette classe Foo.new.i
?
#class
. #class
Personnellement, je pense que les usages quand on les appelle, mais ce self
sont des odeurs de code. Vous pouvez même aller plus loin et implémenter des accesseurs d'instance i
et i=
ce délégué à leurs #class
équivalents, auquel cas vous pouvez le faire Foo.new.i
. Je ne recommande pas de le faire car cela crée une interface déroutante, suggérant que vous modifiez un membre d'objet.