web-dev-qa-db-fra.com

Que signifie @@ variable en Ruby?

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?

143
Andrew

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.

217
Michelle Tilley

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

35
Shaunak

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

1
Tantallion

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.

0
Cagatay Kalan