Quelles sont les variables Ruby précédées du signe double au (@@
)? D'après ma compréhension d'une variable précédée d'un signe at, il s'agit d'une variable d'instance, comme celle-ci en PHP
Version PHP
class Person {
public $name;
public function setName($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
Équivalent rubis
class Person
def set_name(name)
@name = name
end
def get_name()
@name
end
end
Que signifie le signe double de @@
et en quoi diffère-t-il d'un signe unique de?
Une variable préfixée par @
est une variable d'instance _, tandis qu'une variable préfixée par @@
est une variable de classe_. Découvrez l'exemple suivant. sa sortie se trouve dans les commentaires à la fin des lignes puts
:
class Test
@@shared = 1
def value
@@shared
end
def value=(value)
@@shared = value
end
end
class AnotherTest < Test; end
t = Test.new
puts "t.value is #{t.value}" # 1
t.value = 2
puts "t.value is #{t.value}" # 2
x = Test.new
puts "x.value is #{x.value}" # 2
a = AnotherTest.new
puts "a.value is #{a.value}" # 2
a.value = 3
puts "a.value is #{a.value}" # 3
puts "t.value is #{t.value}" # 3
puts "x.value is #{x.value}" # 3
Vous pouvez voir que @@shared
est partagé entre les classes; définir la valeur dans une instance de one modifie la valeur de toutes les autres instances de cette classe et même des classes enfants, où une variable nommée @shared
, avec un @
, ne serait pas.
[Mettre à jour]
Comme Phrogz le mentionne dans les commentaires, c'est un idiome courant en Ruby de suivre les données de niveau classe avec une variable d'instance sur la classe elle-même. Cela peut être un sujet difficile à comprendre, et il y a beaucoup de lectures supplémentaires sur le sujet, mais pensez que cela modifie la classe Class
, mais seulement l'instance de Class
classe avec laquelle vous travaillez. Un exemple:
class Polygon
class << self
attr_accessor :sides
end
end
class Triangle < Polygon
@sides = 3
end
class Rectangle < Polygon
@sides = 4
end
class Square < Rectangle
end
class Hexagon < Polygon
@sides = 6
end
puts "Triangle.sides: #{Triangle.sides.inspect}" # 3
puts "Rectangle.sides: #{Rectangle.sides.inspect}" # 4
puts "Square.sides: #{Square.sides.inspect}" # nil
puts "Hexagon.sides: #{Hexagon.sides.inspect}" # 6
J'ai inclus l'exemple Square
(qui affiche nil
) pour démontrer que cela peut ne pas se comporter à 100% comme prévu; le article I lié ci-dessus contient de nombreuses informations supplémentaires sur le sujet.
Notez également que, comme pour la plupart des données, vous devez être extrêmement prudent avec les variables de classe dans un environnement multithreaded , comme indiqué dans le commentaire de dmarkow.
@
- Variable d'instance d'une classe@@
- Variable de classe, également appelée variable statique dans certains cas
Une variable de classe est une variable partagée par toutes les instances d'une classe. Cela signifie qu'il n'existe qu'une seule valeur de variable pour tous les objets instanciés à partir de cette classe. Si une instance d'objet modifie la valeur de la variable, cette nouvelle valeur sera essentiellement modifiée pour toutes les autres instances d'objet.
Une autre façon de penser aux variables de classe est d'utiliser les variables globales dans le contexte d'une classe unique ..__ Les variables de classe sont déclarées en préfixant le nom de la variable avec deux caractères @
(@@
). Les variables de classe doivent être initialisées au moment de la création
@@
désigne une variable de classe, c’est-à-dire qu’elle peut être héritée.
Cela signifie que si vous créez une sous-classe de cette classe, elle héritera de la variable. Donc, si vous avez une classe Vehicle
avec la variable de classe @@number_of_wheels
, alors si vous créez un class Car < Vehicle
, la variable de classe @@number_of_wheels
sera aussi présente
Les modules @ et @@ in fonctionnent également différemment lorsqu'une classe étend ou inclut ce module.
Donc donné
module A
@a = 'module'
@@a = 'module'
def get1
@a
end
def get2
@@a
end
def set1(a)
@a = a
end
def set2(a)
@@a = a
end
def self.set1(a)
@a = a
end
def self.set2(a)
@@a = a
end
end
Ensuite, vous obtenez les résultats ci-dessous affichés sous forme de commentaires
class X
extend A
puts get1.inspect # nil
puts get2.inspect # "module"
@a = 'class'
@@a = 'class'
puts get1.inspect # "class"
puts get2.inspect # "module"
set1('set')
set2('set')
puts get1.inspect # "set"
puts get2.inspect # "set"
A.set1('sset')
A.set2('sset')
puts get1.inspect # "set"
puts get2.inspect # "sset"
end
class Y
include A
def doit
puts get1.inspect # nil
puts get2.inspect # "module"
@a = 'class'
@@a = 'class'
puts get1.inspect # "class"
puts get2.inspect # "class"
set1('set')
set2('set')
puts get1.inspect # "set"
puts get2.inspect # "set"
A.set1('sset')
A.set2('sset')
puts get1.inspect # "set"
puts get2.inspect # "sset"
end
end
Y.new.doit
Utilisez donc @@ in pour les variables communes à toutes les utilisations et utilisez @ in pour les variables que vous souhaitez séparer pour chaque contexte d'utilisation.
Les réponses sont partiellement correctes car @@ est en fait une variable de classe qui correspond à une hiérarchie de classes, ce qui signifie qu'elle est partagée par une classe, ses instances, ses classes descendantes et leurs instances.
class Person
@@people = []
def initialize
@@people << self
end
def self.people
@@people
end
end
class Student < Person
end
class Graduate < Student
end
Person.new
Student.new
puts Graduate.people
Cela produira
#<Person:0x007fa70fa24870>
#<Student:0x007fa70fa24848>
Il n'y a donc qu'une seule et même variable @@ pour les classes Personne, Étudiant et Graduate et toutes les méthodes de classe et d'instance de ces classes font référence à la même variable.
Il existe un autre moyen de définir une variable de classe définie sur un objet de classe (rappelez-vous que chaque classe est en fait une instance de quelque chose qui est en réalité la classe, mais c'est une autre histoire). Vous utilisez la notation @ au lieu de @@ mais vous ne pouvez pas accéder à ces variables à partir de méthodes d'instance. Vous devez avoir des wrappers de méthode de classe.
class Person
def initialize
self.class.add_person self
end
def self.people
@people
end
def self.add_person instance
@people ||= []
@people << instance
end
end
class Student < Person
end
class Graduate < Student
end
Person.new
Person.new
Student.new
Student.new
Graduate.new
Graduate.new
puts Student.people.join(",")
puts Person.people.join(",")
puts Graduate.people.join(",")
Ici, @people est unique par classe au lieu de hiérarchie de classe car il s'agit en fait d'une variable stockée sur chaque instance de classe. C'est la sortie:
#<Student:0x007f8e9d2267e8>,#<Student:0x007f8e9d21ff38>
#<Person:0x007f8e9d226158>,#<Person:0x007f8e9d226608>
#<Graduate:0x007f8e9d21fec0>,#<Graduate:0x007f8e9d21fdf8>
Une différence importante est que vous ne pouvez pas accéder à ces variables de classe (ou à des variables d'instance de classe que vous pouvez dire) directement à partir de méthodes d'instance car @people dans une méthode d'instance ferait référence à une variable d'instance de cette instance spécifique des classes Person, Student ou Graduate. .
Ainsi, alors que d'autres réponses indiquent correctement que @myvariable (avec une notation @ unique) est toujours une variable d'instance, cela ne signifie pas nécessairement qu'il ne s'agit pas d'une seule variable partagée pour toutes les instances de cette classe.