ruby中的复制 dup clone
Ruby內置的方法Object#clone和Object#dup可以用來copy一個對象,兩者區別是dup只復制對象的內容,而clone還復制與對象相關聯的內容,如singleton method
[ruby] view plaincopyprint?
s = "cat"
def s.upcase
"CaT"
end
s_dup = s.dup
s_clone = s.clone
s_dup.upcase #=> "CAT" (singleton method not copied)
s_clone.upcase #=> "CaT" (uses singleton method)
dup和clone都是淺復制Shallow Copy,也就是只能復制接受方的內容,而如果接受方包含到其他對象的引用,那么就只是會復制這些引用了。
[ruby] view plaincopyprint?
arr1 = [ 1, "flipper", 3 ]
arr2 = arr1.dup
arr2[2] = 99
arr2[1][2] = 'a'
arr1 #=> [1, "flapper", 3]
arr2 #=> [1, "flapper", 99]
可以看到arr1中有一個到String對象的引用,從而arr2也復制了這個引用,當arr2中修改這個引用時,arr1中的也會發生變化。
如果要進行深復制Deep Copy,可以聰明的采用Marshal模塊
[ruby] view plaincopyprint?
arr1 = [ 1, "flipper", 3 ]
arr2 = Marshal.load(Marshal.dump(arr1))
arr2[2] = 99
arr2[1][2] = 'a'
arr1 #=> [1, "flipper", 3]
arr2 #=> [1, "flapper", 99]
現在就會發現arr2中對String對象的修改不會導致arr1的變化了,因為深了。。。不過Marshal模塊并不能把所有的對象都序列化
在class中還有一個與對象復制相關的特殊方法initialize_copy,這個方法會在信息復制完成后執行,看下面這個示例
[ruby] view plaincopyprint?
class Document
attr_accessor :title, :text
attr_reader :timestamp
def initialize(title, text)
@title, @text = title, text
@timestamp = Time.now
end
end
doc1 = Document.new("Random Stuff", "Haha")
sleep 10
doc2 = doc1.clone
doc1.timestamp == doc2.timestamp #=> true
也就是兩個對象是完全一樣的,構造函數initialize被跳過了,所以兩個對象的時間戮timestamp是相同的。如果要采用執行復制操作時的時間,我們可以通過給Document類添加initialize_copy方法來實現。initialize_copy讓程序員能完全控制對象復制的狀態
[ruby] view plaincopyprint?
class Document #Reopen the class
def initialize_copy(other)
@timestamp = Time.now
end
end
doc3 = Document.new("More Stuff", "Haha")
sleep 10
doc4 = doc1.clone
doc3.timestamp == doc4.timestamp #=> false
再次感慨Ruby的魅力。。。
PS:以上內容主要來自The Ruby Way
用Ruby復制一個對象(object)也許沒有你想像的那么容易. 今天我google了半天, 做個總結吧.
先從最簡單的開始, b = a 是復制嗎? 看代碼說話:
>> a= [0,[1,2]]
>> b=a
>> b[0]=88
>> b[1][0]=99
>> b
=> [88, [99, 2]]
>> a
=> [88, [99, 2]]
從上面代碼發現, 一但修改b, 原來的a也同時被改變了. 甚至:
>> b.equal?(a)
=> true
原來b跟a根本就是同一個object, 只是馬甲不一樣罷了. 所以b = a不是復制.
那 b = a.dup呢?? 還是看代碼:
>> a= [0,[1,2]]
>> b=a.dup
>> b[0]=88
>> b[1][0]=99
>> b
=> [88, [99, 2]]
>> a
=> [0, [99, 2]]
情況似乎有所好轉, 在修改b后, a還是有一部分被修改了.(0沒有變,但原來的1變成了99).
所以dup有時候是復制(如在Array只有一級時), 但有時不是復制哦.
再來一個, b = a.clone呢? 上代碼:
>> a= [0,[1,2]]
>> b=a.clone
>> b[0]=88
>> b[1][0]=99
>> b
=> [88, [99, 2]]
>> a
=> [0, [99, 2]]
情況幾乎跟dup一模一樣. 所以clone也不一定可以相信哦!
原來ruby中的dup和clone都是shallow復制, 只針對object的第一級屬性.
汗, 難道在Ruby中沒有辦法復制對像嗎? 也不完全是, 看這個:
>> a= [0,[1,2]]
>> b=Marshal.load(Marshal.dump(a))
>> b[0]=88
>> b[1][0]=99
>> b
=> [88, [99, 2]]
>> a= [0,[1,2]]
=> [0, [1, 2]]
修改b后a沒有被改變!!! 似乎終于成功找到復制的辦法了!!!
為什么要加"似乎"呢? 因為有些object是不能被Marshal.dump的.如:
>> t=Object.new
>> def t.test; puts ‘test’ end
>> Marshal.dump(t)
TypeError: singleton can’t be dumped
from (irb):59:in `dump’
from (irb):59
更完善的復制方案可以考慮給ruby增加一個deep clone功能, 可以參考以下鏈接:
http://d.hatena.ne.jp/pegacorn/20070417/1176817721
轉載于:https://www.cnblogs.com/qinyan20/p/9674004.html
總結
以上是生活随笔為你收集整理的ruby中的复制 dup clone的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于数组的题
- 下一篇: 互联网分布式架构技术概述