2011-05-04 28 views
126

¿Qué son las variables Ruby precedidas con doble en los signos (@@)? Mi comprensión de una variable precedido por una arroba es que es una variable de instancia, como esto en PHP:¿Qué significa @@ variable en Ruby?

versión de PHP

class Person { 

    public $name; 

    public function setName($name) { 
     $this->name = $name; 
    } 

    public function getName() { 
     return $this->name; 
    } 
} 

Rubí equivalente

class Person 

    def set_name(name) 
     @name = name 
    end 

    def get_name() 
     @name 
    end 
end 

Lo que hace el doble en sign, @@, y ¿cómo se diferencia de un solo en el signo?

+77

No lo sé, pero tengo la sensación de que me está mirando. Tengo un poco de miedo para codificar en Ruby ahora ... – corsiKa

+0

TL; DR para el público: 99 veces de cada 100, usaría variables de "instancia de clase" (métodos '@' dentro de 'self') no variables de clase ('@@'). Vea la letanía de razones por las cuales en las respuestas a continuación. – WattsInABox

Respuesta

188

Una variable con el prefijo @ es un instancia de variable, mientras que uno con el prefijo @@ es una clase variable. Mira el siguiente ejemplo; su salida es en los comentarios al final de las líneas 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 

Se puede ver que @@shared se comparte entre las clases; establecer el valor en una instancia de uno cambia el valor para todas las demás instancias de esa clase e incluso clases secundarias, donde una variable llamada @shared, con una @, no lo sería.

[Actualización]

Como Phrogz menciona en los comentarios, es un idioma común en Ruby para realizar un seguimiento de datos de nivel de clase con una instancia de variable en la propia clase. Esto puede ser un tema difícil para su mente, y hay un montón de additional reading sobre el tema, pero piense en ello como la modificación de la clase Class, pero solo la instancia de la clase Class con la que está trabajando. Un ejemplo:

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 

que incluyó la Square ejemplo (que da salida a nil) para demostrar que esto no se puede comportar 100% como se esperaba; el article I linked above tiene mucha información adicional sobre el tema.

También tenga en cuenta que, como con la mayoría de los datos, debe tener mucho cuidado con las variables de clase en un multithreaded environment, según el comentario de dmarkow.

+1

Esta respuesta sería perfecta en mi humilde opinión si incluyese código que muestre cómo puede usar una variable de instancia en el nivel de clase para rastrear los datos de nivel de clase sin el comportamiento "extraño" de compartir datos entre subclases. – Phrogz

+2

También me gustaría señalar que las variables de clase pueden ser peligrosas/poco fiables en un entorno de subprocesos múltiples (por ejemplo, Rails) –

+0

Hmm ... de alguna manera suena como variables estáticas en PHP, pero la parte de herencia es diferente. No creo que PHP tenga algo así como esto. – Andrew

9

@@ denota una variable de clase, es decir, se puede heredar.

Esto significa que si crea una subclase de esa clase, heredará la variable. Así que si usted tiene una clase Vehicle con la clase variable de @@number_of_wheels continuación, si se crea un class Car < Vehicle entonces también tendrá la clase variable de @@number_of_wheels

+0

¿Qué significa eso? – Andrew

+0

Esto significa que si crea una subclase de esa clase, heredará la variable. Entonces, si tienes una clase 'Vehículo' con la variable de clase' @@ number_of_wheels', entonces si creas una 'clase Auto

+12

Si tengo una 'clase Vehículo 'with' @ number_of_wheels', then 'class Car

32

@ - variable de instancia de una clase
@@ - Variable de clase, también llamado como variable estática en algunos casos

Una variable de clase es una variable que se comparte entre todas las instancias de una clase. Esto significa que solo existe un valor de variable para todos los objetos instanciados de esta clase.Si una instancia de objeto cambia el valor de la variable, ese nuevo valor esencialmente cambiará para todas las demás instancias de objetos.

Otra forma de pensar al pensar en variables de clase es como variables globales dentro del contexto de una clase única. Las variables de clase se declaran prefijando el nombre de la variable con dos caracteres @ (@@). Las variables de clase se deben iniciar en tiempo de creación

0

@ = variable de instancia donde como @@ = variable de clase

la variable de instancia es como, lo que es compartir con instancia/objetos de una clase con el fin de acceder al variable de instancia necesitamos definir los setters y getters para esa variable de instancia

mientras que la variable de clase es similar, que se comparte entre todas las instancias/objetos de una clase o en otras palabras, puede decir que es un variable, por lo que se puede acceder a la variable global globalmente

0

@ y @@ en los módulos también funcionan de manera diferente cuando una clase amplía o incluye ese módulo.

Así da

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 

Luego de obtener los resultados a continuación se muestra como comentarios

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 

a fin de utilizar @@ en los módulos de variables que desea común a todos sus usos, y el uso de módulos @ para las variables que desea separar para cada contexto de uso.