2009-12-26 87 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