2009-12-26 85 views
7
>> 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

重写dup方法解决这个问题,据我可以告诉:

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

这是否有不利的一面,我没有看到?为什么不将它内置到Ruby中?

回答

14

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

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

虽然Ruby中的一些对象是直接的。它们通过价值传递,只能有一个这个价值,因此不能被欺骗。这些是任何(小)整数,true,false,符号和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获得的副本,红宝石选择不立即数上定义dup

你的问题比看起来更复杂。有关红宝石核心的some discussion,以便如何使这更容易。此外,其他类型的数字对象(浮点数,双数,有理数和复数)也不能被欺骗,尽管它们也不是立即数。

注意的ActiveSupport(轨道的一部分)提供的方法duplicable?上的所有对象

+1

ActiveSupport,不是Rails,提供了'可复制?'方法。所以你可以安装ActiveSupport并且需要它('require'active_support''),如果你需要这个(和其他许多)实用程序方法。 – henrikhodne 2009-12-28 18:11:25

+0

确实。更新。 – 2009-12-28 21:37:20

+0

链接应该被https://bugs.ruby-lang.org/issues/1844取代。此外,该功能被拒绝,因为显然没有取得进展。 – 2014-08-20 05:44:10

2

您定义的dup()函数的问题是它不会返回该对象的副本,而是返回该对象本身。这不是duplicate程序应该执行的操作。

我不知道红宝石,但一个可能的原因,我能想到的dup没有为数字定义的是,一些是基本类型,因此,做这样的事情:自动

>> a = 5 
>> b = a 

会将值5分配到变量b中,而不是使ba指向内存中的相同值。

+0

这是Ruby的究竟是干什么的,所以当你用我的方法用一个数值类型,它会返回一个新的副本。 (对于任何其他类型,它将返回对原始参考) – 2009-12-26 19:41:27

+0

我想这是事实。从功能的角度来看,那么你的代码可能没有问题。然而,Ruby不会内置它的原因很可能是因为它只是复制了Ruby基本类型的内置赋值功能。 – cmptrgeekken 2009-12-26 20:08:45