微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

类变量覆盖

如何解决类变量覆盖

我在玩类变量,我知道我可以覆盖子类中的类变量,但我没有意识到在哪里调用方法很重要。例如;

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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?