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
我想知道的是,我应该使用哪一个? 每个的好处和缺点是什么?
类变量是:
类实例变量是:
我还应该考虑什么?
答案 0 :(得分:3)
我最近发现ActiveSupport定义了class_inheritable_accessor
,它执行类实例变量所做的工作,其优点是对象不会在继承之间共享,并且在子类化时可以为变量设置默认值。
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
更多信息here
为了完整性:在两个呈现选项中,我更喜欢使用类实例变量,因为它通常是预期的行为。
答案 1 :(得分:3)
永远不要在Ruby中使用类变量。它们会导致继承问题。始终使用类实例变量。
答案 2 :(得分:1)
您还可以选择在类级别声明实例变量:
class Foo
@bar = 'baz'
def Foo.print
puts @bar
end
end
总的来说,我会避免使用类变量,因为共享跨越继承模型通常非常令人惊讶且不明显;说实话,我不确定他们真正提供什么样的效用,除了不是全球化的全球。
如果你需要一个'scoped'全局变量,我会选择具有访问器的类级实例变量。你可以避免继承“惊喜”,同时仍然保持封装。
答案 3 :(得分:1)
类实例变量通常比类变量更有用且更不令人惊讶,因此您应该使用它们。
现在,我将在StackOverflow上的Ruby回答中给出一些令人难以忍受的详细信息:
要声明或引用类实例变量,您需要处于类范围并使用单个@符号。这会将变量放在该类的单例类实例上。
不幸的是,当您在类范围内并使用def
关键字时,您的方法将被放置在该类的实例方法列表中,并在中执行实例范围,因此他们的@ -sign变量将位于他们所在的实例上。
我们想要的是在类上定义方法,而不是在其实例上定义方法。这实际意味着这些方法位于类对象的单例类的实例方法列表中。 (唷!)
总而言之:在类对象Foo
的单例类中切换和定义方法至少有四个习惯用法:
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]
(一旦你考虑class_eval
和define_method
等等,可能还有六种方法可以做到这一点,但现在应该让你满意。:-))
最后要注意的是:类实例变量只能通过它们定义的类来获得。如果你尝试从(或通过)子类调用任何这些方法,那么方法将会执行,但@变量都将为nil,因为self
将是子类的类对象,而不是父类的类对象
class Bar < Foo
end
p [Bar.a, Bar.b, Bar.c, Bar.d]
#=> [nil, nil, nil, nil]