为什么数字不支持.dup?

时间:2009-12-26 19:28:07

标签: ruby numbers abstraction

>> a = 5
=> 5
>> b = "hello, world!"
=> "hello, world!"
>> b.dup
=> "hello, world!"
>> a.dup
TypeError: can't dup Fixnum
    from (irb):4:in `dup'
    from (irb):4

我知道Ruby会在每次为新变量分配整数时制作副本,但为什么Numeric#dup会引发错误?

这不会破坏抽象,因为所有对象都应该正确响应.dup吗?

据我所知,重写dup方法将解决问题:

>> class Numeric
>>   def dup()
>>     self
>>   end
>> end

这有没有我看不到的缺点?为什么不将它内置到Ruby中?

2 个答案:

答案 0 :(得分:15)

Ruby中的大多数对象都是通过引用传递的,可以复制。例如:

s = "Hello"
t = s      # s & t reference to the same string
t.upcase!  # modifying either one will affect the other
s # ==> "HELLO"

但Ruby中的一些对象是即时的。它们按值传递,只能有一个这个值,因此不能被欺骗。这些是任何(小)整数,truefalse,符号和nil。许多浮点数在64位系统上的Ruby 2.0中也是最重要的。

在这个(荒谬的)例子中,任何“42”都将保存相同的实例变量。

class Fixnum
  attr_accessor :name
  alias_method :original_to_s, :to_s
  def to_s
    name || original_to_s
  end
end
42.name = "The Answer"
puts *41..43  # =>  41, The Answer, 43

由于您通常希望something.dup.name = "new name"不影响使用dup获得的副本之外的任何其他对象,因此Ruby选择不在immediates上定义dup

你的问题比它看起来更复杂。 ruby-core上有some discussion关于如何使这更容易。此外,其他类型的数字对象(浮动,bignums,有理数和复数)也不能被欺骗,尽管它们也不是中立的。

请注意,ActiveSupport(rails的一部分)在所有对象上提供方法duplicable?

答案 1 :(得分:3)

您定义的dup()函数的问题是它不返回对象的副本,而是返回对象本身。这不是duplicate程序应该做的事情。

我不知道Ruby,但我可以想到dup没有为数字定义的一个原因是数字是一个基本类型,因此做了类似的事情:

>> a = 5
>> b = a

会自动将值5分配给变量b,而不是让ba指向内存中的相同值。