Variable de instancia de clase Ruby frente a variable de clase

Resuelto Elmor asked hace 11 años • 8 respuestas

Leí ¿Cuándo se configuran las variables de instancia de Ruby? pero tengo dudas sobre cuándo usar variables de instancia de clase.

Las variables de clase son compartidas por todos los objetos de una clase, las variables de instancia pertenecen a un objeto. No queda mucho espacio para usar variables de instancia de clase si tenemos variables de clase.

¿Alguien podría explicar la diferencia entre estos dos y cuándo usarlos?

Aquí hay un ejemplo de código:

class S
  @@k = 23
  @s = 15
  def self.s
    @s
  end
  def self.k
     @@k
  end

end
p S.s #15
p S.k #23

Actualización: ¡ahora lo entiendo! Las variables de instancia de clase no se pasan a lo largo de la cadena de herencia.

Elmor avatar Apr 03 '13 03:04 Elmor
Aceptado

Variable de instancia en una clase:

class Parent
  @things = []
  def self.things
    @things
  end
  def things
    self.class.things
  end
end

class Child < Parent
  @things = []
end

Parent.things << :car
Child.things  << :doll
mom = Parent.new
dad = Parent.new

p Parent.things #=> [:car]
p Child.things  #=> [:doll]
p mom.things    #=> [:car]
p dad.things    #=> [:car]

variables de clase:

class Parent
  @@things = []
  def self.things
    @@things
  end
  def things
    @@things
  end
end

class Child < Parent
end

Parent.things << :car
Child.things  << :doll

p Parent.things #=> [:car,:doll]
p Child.things  #=> [:car,:doll]

mom = Parent.new
dad = Parent.new
son1 = Child.new
son2 = Child.new
daughter = Child.new

[ mom, dad, son1, son2, daughter ].each{ |person| p person.things }
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]

Con una variable de instancia en una clase (no en una instancia de esa clase), puede almacenar algo común a esa clase sin que las subclases también lo obtengan automáticamente (y viceversa). Con las variables de clase, tiene la comodidad de no tener que escribir self.classdesde un objeto de instancia y (cuando sea conveniente) también puede compartir automáticamente en toda la jerarquía de clases.


Fusionarlos en un solo ejemplo que también cubre variables de instancia en instancias:

class Parent
  @@family_things = []    # Shared between class and subclasses
  @shared_things  = []    # Specific to this class

  def self.family_things
    @@family_things
  end
  def self.shared_things
    @shared_things
  end

  attr_accessor :my_things
  def initialize
    @my_things = []       # Just for me
  end
  def family_things
    self.class.family_things
  end
  def shared_things
    self.class.shared_things
  end
end

class Child < Parent
  @shared_things = []
end

Y luego en acción:

mama = Parent.new
papa = Parent.new
joey = Child.new
suzy = Child.new

Parent.family_things << :house
papa.family_things   << :vacuum
mama.shared_things   << :car
papa.shared_things   << :blender
papa.my_things       << :quadcopter
joey.my_things       << :bike
suzy.my_things       << :doll
joey.shared_things   << :puzzle
suzy.shared_things   << :blocks

p Parent.family_things #=> [:house, :vacuum]
p Child.family_things  #=> [:house, :vacuum]
p papa.family_things   #=> [:house, :vacuum]
p mama.family_things   #=> [:house, :vacuum]
p joey.family_things   #=> [:house, :vacuum]
p suzy.family_things   #=> [:house, :vacuum]

p Parent.shared_things #=> [:car, :blender]
p papa.shared_things   #=> [:car, :blender]
p mama.shared_things   #=> [:car, :blender]
p Child.shared_things  #=> [:puzzle, :blocks]  
p joey.shared_things   #=> [:puzzle, :blocks]
p suzy.shared_things   #=> [:puzzle, :blocks]

p papa.my_things       #=> [:quadcopter]
p mama.my_things       #=> []
p joey.my_things       #=> [:bike]
p suzy.my_things       #=> [:doll] 
Phrogz avatar Apr 02 '2013 20:04 Phrogz

Fuente

Disponibilidad para instanciar métodos

  • Las variables de instancia de clase están disponibles sólo para los métodos de clase y no para los métodos de instancia.
  • Las variables de clase están disponibles tanto para métodos de instancia como para métodos de clase.

Heredabilidad

  • Las variables de instancia de clase se pierden en la cadena de herencia.
  • Las variables de clase no lo son.
class Vars

  @class_ins_var = "class instance variable value"  #class instance variable
  @@class_var = "class variable value" #class  variable

  def self.class_method
    puts @class_ins_var
    puts @@class_var
  end

  def instance_method
    puts @class_ins_var
    puts @@class_var
  end
end

Vars.class_method

puts "see the difference"

obj = Vars.new

obj.instance_method

class VarsChild < Vars


end

VarsChild.class_method
Sachin Saxena avatar Jun 08 '2014 10:06 Sachin Saxena

Creo que la principal (¿única?) diferencia es la herencia:

class T < S
end

p T.k
=> 23

S.k = 24
p T.k
=> 24

p T.s
=> nil

Las variables de clase son compartidas por todas las "instancias de clase" (es decir, subclases), mientras que las variables de instancia de clase son específicas sólo de esa clase. Pero si nunca tienes intención de ampliar tu clase, la diferencia es puramente académica.

bioneuralnet avatar Apr 02 '2013 20:04 bioneuralnet

Como dijeron otros, las variables de clase se comparten entre una clase determinada y sus subclases. Las variables de instancia de clase pertenecen exactamente a una clase; sus subclases están separadas.

¿Por qué existe este comportamiento? Bueno, todo en Ruby es un objeto, incluso las clases. Eso significa que cada clase tiene un objeto de la clase Class(o más bien, una subclase de Class) correspondiente. (Cuando dices class Foo, en realidad estás declarando una constante Fooy asignándole un objeto de clase). Y cada objeto Ruby puede tener variables de instancia, por lo que los objetos de clase también pueden tener variables de instancia.

El problema es que las variables de instancia en los objetos de clase realmente no se comportan de la forma en que normalmente se desea que se comporten las variables de clase. Por lo general, desea que una variable de clase definida en una superclase se comparta con sus subclases, pero no es así como funcionan las variables de instancia: la subclase tiene su propio objeto de clase y ese objeto de clase tiene sus propias variables de instancia. Entonces introdujeron variables de clase separadas con el comportamiento que es más probable que desees.

En otras palabras, las variables de instancia de clase son una especie de accidente del diseño de Ruby. Probablemente no deberías usarlos a menos que sepas específicamente que son lo que estás buscando.

Becca Royal-Gordon avatar Feb 01 '2015 15:02 Becca Royal-Gordon