【问题标题】:Sub-classing Fixnum in rubyruby 中的子类 Fixnum
【发布时间】:2009-07-08 01:57:41
【问题描述】:

所以我知道您不应该直接继承 Fixnum、Float 或 Integer,因为它们没有#new 方法。使用 DelegateClass 似乎可行,但这是最好的方法吗?有谁知道这些类没有#new 的原因是什么?

我需要一个行为类似于 Fixnum 的类,但有一些额外的方法,我希望能够在类中通过 self 引用它的值,例如:

class Foo < Fixnum
  def initialize value
    super value
  end

  def increment
    self + 1
  end
end

Foo.new(5).increment + 4 # => 10

【问题讨论】:

  • 告诉我们您真正想要做什么(最终目标),我们会尽力告诉您最好的方法。我认为子分类在这里不合适。

标签: ruby inheritance


【解决方案1】:

您可以自己轻松设置快速转发实现:

class MyNum
  def initialize(number)
    @number = number
  end

  def method_missing(name, *args, &blk)
    ret = @number.send(name, *args, &blk)
    ret.is_a?(Numeric) ? MyNum.new(ret) : ret
  end
end

然后你可以在 MyNum 上添加任何你想要的方法,但是你需要在这些方法中对 @number 进行操作,而不是能够直接调用 super。

【讨论】:

  • 嗯。但是如果你做了 MyNum.new(2) + MyNum.new(3),你不会得到一个 Fixnum 而不是 MyNum 实例吗?我认为您需要将 @number.send 包装在 MyNum.new 中
  • 我更新了我的答案,以确保如果原始响应是数字,您返回 MyNum。
  • MyNum 能否实现为 MyNum.new(5) == 5 AND 5 == MyNum.new(5)?
【解决方案2】:

IIRC,Ruby 的主要实现将 Fixnums 存储为立即值,使用单词的一些低位将其标记为 Fixnum,而不是指向堆上对象的指针。这就是为什么在 32 位机器上,Fixnums 只是 29 位(或其他)而不是一个完整的字。

因此,您不能将方法添加到 Fixnum 的单个“实例”,也不能对其进行子类化。

如果您对“类 Fixnum”类一无所知,您可能必须创建一个具有 Fixnum 实例变量的类,并适当地转发方法调用。

【讨论】:

  • 啊,我明白了。还有其他我可以子类的类吗? Numeric 有一个#new,但它不带任何参数,所以我认为它是一个抽象类。
  • 嗯。我已经有一段时间没有接触过 Ruby,我也记不清数字类树是如何布局的了。
  • 唯一明显的候选者是 BigDecimal。
  • 将实例方法添加到单个 FixNum 实例的解决方法:class Fixnum;很有趣; to_s.to_sym == :'37' ? “有趣”:超级;结尾;结束
【解决方案3】:

你不能扩展 FixNum 本身吗?喜欢...

class Fixnum
  def even?
    self % 2 == 0
  end
end

42.even?

【讨论】:

  • 我可以,但我不愿意。此外,Fixnum 没有#new,我需要能够向#initialize 添加功能。
  • 猴子补丁应该小心使用。仅仅为了一个特定的用例而污染一个 Ruby 核心类是很危险的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
相关资源
最近更新 更多