如何解决类变量覆盖
我在玩类变量,我知道我可以覆盖子类中的类变量,但我没有意识到在哪里调用类方法很重要。例如;
class Vehicle
@@wheels = 4
def self.wheels
@@wheels
end
end
puts Vehicle.wheels #4
puts Vehicle.wheels #4
puts Vehicle.wheels #4
class Motorcycle < Vehicle
@@wheels = 2
end
puts
语句输出 4,这对我来说都是有意义的,因为我认为在从 @@wheels
类实例化对象之前,您 Motorcycle
不会被覆盖。所以我做了这个:
class Vehicle
@@wheels = 4
def self.wheels
@@wheels
end
end
class Motorcycle < Vehicle
@@wheels = 2
end
puts Vehicle.wheels #2
puts Vehicle.wheels #2
puts Vehicle.wheels #2
现在,一旦我将这三行移动到类 Motorcycle
之后,它们输出 2... 即使 Motorcycle
对象尚未实例化。这让我很困惑。详细说明这里发生了什么?是因为当我们尝试访问它时加载了类变量吗?这怎么可能?
解决方法
首先,与实例化无关;这是一个类变量,而不是一个实例变量。你的代码从不实例化任何东西;也不是,正如所写的,它不需要。我们只是在谈论一些课程。但是类在 Ruby 中是一流的对象,所以没问题。
其次,顺序很重要,因为在 Ruby 中所有语句都是可执行的。当你说
class Motorcycle < Vehicle
@@wheels = 2
end
...所有这些代码都立即执行,就在你说出它的那一刻——当 Ruby 按照指令沿着页面走时遇到它的那一刻。该代码不仅仅是在未来某个时间要遵守的模板;它说:“创建一个摩托车类并将其类变量 wheels
设置为 2
,现在。”
第三,你没有“压倒”任何东西。在 Motorcycle 类中,@@wheels
是 与您之前为 Vehicle 定义的类变量 @@wheels
完全相同。它不是“覆盖”它的其他变量。这是一个单一的值,就像一种命名空间的全局变量,可从类、任何子类及其任何实例访问。
有关更多信息,请参阅(例如):
如果你想要一些你可以覆盖的东西,你正在寻找的可能更像是类上下文中的实例变量,通常称为“类实例变量”——例如像这样:
class Vehicle
@wheels = 4
class << self
attr_reader :wheels
end
end
class Motorcycle < Vehicle
@wheels = 2
end
puts Vehicle.wheels # 4
puts Motorcycle.wheels # 2
,
所有出现的 @@wheels
都指向完全相同的变量。首先将其设置为 4,然后将其设置为 2。为什么它的值为 2 会让您感到惊讶?如果您想为两者使用单独的变量,请改用 @wheels
(如 matt 建议)。
说到这里(这是我写这个答案的唯一原因,因为马特已经在他的答案中涵盖了其他所有内容),您对这个“变量”的使用表明它应该是一个不变的属性相应的班级。也就是说,每辆摩托车都应该有 2 个轮子。在这种情况下,将其设为类的常量可能更有意义:
class Motorcycle < Vehicle
WHEELS = 2
end
class Unicycle < Vehicle
WHEELS = 1
end
并将其用作
puts Motorcycle::WHEELS
如果你有一个变量v,你只知道它是Vehicle的一些子类,你可以写
puts v.class::WHEELS
您是否也在类 Vehicle 本身中定义了 WHEELS,这是一个设计问题。如果您打算将 Vehicle
视为抽象类,则在其中定义固定数量的轮子是没有意义的。对于正交性,你可以通过做一个
class Vehicle
WHEELS = nil
end
如果你想,或者只是不定义它并依赖于你的代码会引发异常的事实,如果你试图访问“只是一辆普通车辆”的东西的轮子。
如果您确实想实例化 Vehicle
,当然可以将那里的常量设置为 4。
但是,在这种情况下,我会考虑允许具有不同轮数的单个实例。 Reliant Robin 是一辆有 3 个轮子的汽车,而卡车有时有 6 或 8 个轮子。因此,为了最大程度的通用性,我会将轮子的数量作为一个实例变量,当然您可以提供一个默认值:
class Vehicle
attr_reader :wheels
def initialize(wheels=4)
@wheels=wheels
end
end
class Motorcycle < Vehicle
attr_reader :wheels
def initialize(wheels=2)
super(wheels)
end
end
m = Motorcycle.new
puts m.wheels
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。