Should I use class variables or class-instance variables for class static variables in Ruby?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Something @@variable = 'Class variable' def give_me @@variable end end class OtherThing @variable = 'Instance variable with an interface' class << self attr_accessor :variable end def give_me self.class.variable end end p Something.new.give_me p OtherThing.new.give_me |
我想知道的是,我应该使用哪一个?每种方法的好处和缺点是什么?
类变量是:
类实例变量是:
我还应该考虑什么?
永远不要在Ruby中使用类变量。它们会导致继承问题。始终使用类实例变量。
我最近发现activesupport定义了
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Foo class_inheritable_accessor :x, :y end Foo.x = 1 class Bar < Foo end Bar.x #=> 1 Bar.x = 3 Bar.x #=> 3 Foo.x #=> 1 |
更多信息在这里
只是为了完整性:在两个已呈现的选项中,我更喜欢使用类实例变量,因为这通常是预期的行为。
类实例变量通常比类变量更有用,更不令人惊讶,因此您可能应该使用它们。
现在,我将在stackoverflow上的一个Ruby答案中详细说明一些您所期望的难以忍受的细节:
要声明或引用类实例变量,需要在类范围内,并使用单个@符号。这会将变量放在该类的singleton类实例上。
不幸的是,当您在类范围内并使用
我们想要的是在类上定义方法,而不是在类的实例上定义方法。这真正意味着这些方法在类对象的singleton类的实例方法列表中。(呸!)
综上所述,在类对象
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 Foo @a, @b, @c, @d = 1, 2, 3, 4 # 1. pass the target to def def Foo.a @a end # 2. pass the target to def, relying on the fact that self # happens to be the class object right now def self.b @b end # switch from class scope to singleton class scope class << self # 3. define a plain accessor in singleton class scope def c @c end # 4. use a macro to define an accessor attr_reader :d end end p [Foo.a, Foo.b, Foo.c, Foo.d] #=> [1, 2, 3, 4] |
(如果你考虑到
最后一个注意事项:类实例变量只能通过在其上定义的类来使用。如果试图从子类(或通过子类)调用这些方法中的任何一个,这些方法将执行,但@variables将全部为零,因为
1 2 3 4 5 | class Bar < Foo end p [Bar.a, Bar.b, Bar.c, Bar.d] #=> [nil, nil, nil, nil] |
您还可以选择在类级别声明实例变量:
1 2 3 4 5 6 7 | class Foo @bar = 'baz' def Foo.print puts @bar end end |
总的来说,我会避免使用类变量,因为跨继承模型的共享通常非常令人惊讶且不明显;老实说,我不确定它们真正提供了什么实用程序,而不是一个不太全局的全局实用程序。
如果您需要一个"作用域"全局变量,我将使用访问器来查找类级实例变量。您可以在保持封装的同时避免继承"意外"。