Ruby class instance variable vs. class variable
我读到"Ruby实例变量什么时候设置?"但是在使用类实例变量时我有两个想法。
类变量由类的所有对象共享,实例变量属于一个对象。如果我们有类变量,就没有足够的空间使用类实例变量。
有人能解释一下这两者的区别以及何时使用它们吗?
下面是一个代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
我现在明白了,类实例变量不是沿着继承链传递的!
类上的实例变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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] |
类变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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] |
通过类上的实例变量(不是该类的实例),您可以存储该类的公共内容,而无需子类自动获取它们(反之亦然)。使用类变量,您可以不必从实例对象写入
将这些合并到一个示例中,该示例还包括实例上的实例变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 |
然后付诸行动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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] |
我相信主要(只是?)不同的是继承:
1 2 3 4 5 6 7 8 9 10 11 12 | class T < S end p T.k => 23 S.k = 24 p T.k => 24 p T.s => nil |
类变量由所有"类实例"(即子类)共享,而类实例变量仅特定于该类。但是,如果你从未打算延长你的课程,这完全是学术上的差异。
#类实例变量仅可用于类方法而不可用于实例方法,而类变量可用于实例方法和类方法。此外,类实例变量在继承链中丢失,而类变量则不丢失。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 |
正如其他人所说,类变量在给定的类及其子类之间共享。类实例变量只属于一个类;它的子类是独立的。
为什么会有这种行为?好吧,Ruby中的所有内容都是对象,甚至是类。这意味着每个类都有一个对应于它的类
问题是,类对象上的实例变量的行为并不像您通常希望类变量的行为那样。您通常希望在超类中定义的类变量与其子类共享,但这不是实例变量的工作方式,子类有自己的类对象,而类对象有自己的实例变量。因此,他们引入了不同的类变量,这些变量具有您更可能想要的行为。
换句话说,类实例变量是Ruby设计的一个意外。你可能不应该使用它们,除非你明确知道它们是你要找的。
虽然使用类实例变量似乎很有用,但是由于类实例变量在子类之间共享,并且可以在单例方法和实例方法中引用,因此存在一个单独的缺点。它们是共享的,因此子类可以更改类实例变量的值,而基类也会受到更改的影响,这通常是不需要的行为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class C @@c = 'c' def self.c_val @@c end end C.c_val =>"c" class D < C end D.instance_eval do def change_c_val @@c = 'd' end end => :change_c_val D.change_c_val (irb):12: warning: class variable access from toplevel =>"d" C.c_val =>"d" |
Rails引入了一种称为class_属性的简便方法。顾名思义,它声明了一个类级属性,其值可以由子类继承。类属性值可以在singleton和instance方法中访问,类实例变量也是如此。然而,rails中class_属性的巨大好处是子类可以改变自己的值,并且不会影响父类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class C class_attribute :c self.c = 'c' end C.c =>"c" class D < C end D.c = 'd' =>"d" C.c =>"c" |