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]
Variable 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 las obtengan automáticamente (y viceversa). Con las variables de clase, tiene la conveniencia de no tener que escribir self.class
desde un objeto de instancia y (cuando lo desee) también obtiene el uso compartido automático en toda la jerarquía de clases.
Fusionando estos 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]
self.things
referencia a un métodothings
en el alcance actual (en el caso de una instancia de una clase, será el método de la instancia), donde haceself.class.things
referencia a unthings
método de la clase del alcance actual (nuevamente en el caso de una instancia de una clase, significaría El método de clase).Creo que la principal (¿solo?) Diferente es la herencia:
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 solo de esa clase. Pero si nunca tiene la intención de extender su clase, la diferencia es puramente académica.
fuente
S.new.s => nil
yS.new.k => 23
.Fuente
Disponibilidad para métodos de instancia
Heredabilidad
fuente
Como otros dijeron, las variables de clase se comparten entre una clase dada 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 deClass
) correspondiente a ella. (Cuando dicesclass Foo
, realmente estás declarando una constanteFoo
y 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 generalmente quieres 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 desee.
En otras palabras, las variables de instancia de clase son una especie de accidente del diseño de Ruby. Probablemente no debería usarlos a menos que sepa específicamente que son lo que está buscando.
fuente
Preguntas frecuentes oficiales sobre Ruby: ¿Cuál es la diferencia entre las variables de clase y las variables de instancia de clase?
La principal diferencia es el comportamiento con respecto a la herencia: las variables de clase se comparten entre una clase y todas sus subclases, mientras que las variables de instancia de clase solo pertenecen a una clase específica.
Las variables de clase de alguna manera pueden verse como variables globales dentro del contexto de una jerarquía de herencia, con todos los problemas que vienen con las variables globales. Por ejemplo, una variable de clase podría (accidentalmente) ser reasignada por cualquiera de sus subclases, afectando a todas las demás clases:
O bien, una clase de antepasado podría reabrirse y cambiarse más tarde, con efectos posiblemente sorprendentes:
Entonces, a menos que sepa exactamente lo que está haciendo y necesite explícitamente este tipo de comportamiento, es mejor que use variables de instancia de clase.
fuente
Para aquellos con antecedentes en C ++, puede estar interesado en una comparación con el equivalente de C ++:
Como podemos ver,
k
es unastatic
variable similar. Esto es 100% como una variable global, excepto que es propiedad de la clase (con el alcance para ser correcto). Esto hace que sea más fácil evitar enfrentamientos entre variables con nombres similares. Al igual que cualquier variable global, solo hay una instancia de esa variable y modificarla siempre es visible para todos.Por otro lado,
s
es un valor específico del objeto. Cada objeto tiene su propia instancia del valor. En C ++, debe crear una instancia para tener acceso a esa variable. En Ruby, la definición de clase es en sí misma una instancia de la clase (en JavaScript, esto se llama prototipo), por lo tanto, puede acceders
desde la clase sin instanciación adicional. La instancia de clase se puede modificar, pero la modificación des
va a ser específica para cada instancia (cada objeto de tipoS
). Por lo tanto, modificar uno no cambiará el valor en otro.fuente
Si bien puede parecer inmediatamente útil utilizar variables de instancia de clase, dado que las variables de instancia de clase se comparten entre las subclases y se puede hacer referencia a ellas dentro de los métodos de instancia única y, existe un inconveniente singular. Se comparten y, por lo tanto, las subclases pueden cambiar el valor de la variable de instancia de clase, y la clase base también se verá afectada por el cambio, que generalmente es un comportamiento indeseable:
Rails presenta un método útil llamado class_attribute. Como su nombre lo indica, declara un atributo de nivel de clase cuyo valor es heredable por subclases. Se puede acceder al valor de class_attribute en métodos singleton y de instancia, como es el caso con la variable de instancia de clase. Sin embargo, el gran beneficio de class_attribute en Rails es que las subclases pueden cambiar su propio valor y no afectarán a la clase principal.
fuente
self.
cada vez que desee acceder al atributoc
, por ejemploself.c
. Los documentos dicendefault:
que se puede pasar un parámetro,class_attribute
pero no parece funcionar debido al punto que acabo de mencionarself
.