使用class_variable_get,但前提是必须这样做
class_variable_get 是更好的方法,除了它对你没有“吸引力”。如果你进入一个类并破坏了封装,那么设置这个额外的障碍来表明你做错了什么是合适的。
为要访问的变量创建访问器方法
如果这些是您的类,并且访问变量不会破坏封装,那么您应该为它们创建类访问器方法以使其更容易和更漂亮:
class Foo
def self.bar
@@bar
end
end
p Foo.bar
但是,如果这是您的类,您确定需要类变量吗?如果您不了解其中的含义(见下文),您实际上可能需要类本身的实例变量:
class Foo
class << self
attr_accessor :bar
end
end
Foo.bar = 42
p Foo.bar
类变量的行为
类变量对新手来说似乎是在类级别存储信息的正确方法,主要是因为名称。它们也很方便,因为无论您是在类的方法中还是在实例方法中,都可以使用相同的语法来读写它们。但是,类变量在一个类及其所有子类之间共享。
例如,考虑以下代码:
class Rectangle
def self.instances
@@instances ||= []
end
def initialize
(@@instances ||= []) << self
end
end
class Square < Rectangle
def initialize
super
end
end
2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]
Square.new
p Square.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>, #<Square:0x25c76d0>]
确认!矩形不是正方形!这是做同样事情的更好方法:
class Rectangle
def self.instances
@instances ||= []
end
def initialize
self.class.instances << self
end
end
class Square < Rectangle
def initialize
super
end
end
2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]
2.times{ Square.new }
p Square.instances
#=> [#<Square:0x25c76d0>, #<Square:0x25c76b8>]
通过在类本身上创建实例变量和访问器方法(恰好是 Class 类的实例,类似于 MyClass = Class.new)类的所有实例(和外部)都有一个共同的、干净的位置读取/写入其他类之间不共享的信息。
请注意,显式跟踪创建的每个实例将防止对“未使用”实例进行垃圾收集。小心使用上述代码。
以更简洁的方式使用class_eval
最后,如果您要使用class_eval,请注意它还有一个块形式,无需解析字符串来评估它:
Foo.class_eval('@@bar') # ugh
Foo.class_eval{ @@bar } # yum