ruby中的复制 dup clone
Ruby內(nèi)置的方法Object#clone和Object#dup可以用來copy一個(gè)對象,兩者區(qū)別是dup只復(fù)制對象的內(nèi)容,而clone還復(fù)制與對象相關(guān)聯(lián)的內(nèi)容,如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都是淺復(fù)制Shallow Copy,也就是只能復(fù)制接受方的內(nèi)容,而如果接受方包含到其他對象的引用,那么就只是會(huì)復(fù)制這些引用了。
[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中有一個(gè)到String對象的引用,從而arr2也復(fù)制了這個(gè)引用,當(dāng)arr2中修改這個(gè)引用時(shí),arr1中的也會(huì)發(fā)生變化。
如果要進(jìn)行深復(fù)制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]
現(xiàn)在就會(huì)發(fā)現(xiàn)arr2中對String對象的修改不會(huì)導(dǎo)致arr1的變化了,因?yàn)樯盍恕!!2贿^Marshal模塊并不能把所有的對象都序列化
在class中還有一個(gè)與對象復(fù)制相關(guān)的特殊方法initialize_copy,這個(gè)方法會(huì)在信息復(fù)制完成后執(zhí)行,看下面這個(gè)示例
[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
也就是兩個(gè)對象是完全一樣的,構(gòu)造函數(shù)initialize被跳過了,所以兩個(gè)對象的時(shí)間戮timestamp是相同的。如果要采用執(zhí)行復(fù)制操作時(shí)的時(shí)間,我們可以通過給Document類添加initialize_copy方法來實(shí)現(xiàn)。initialize_copy讓程序員能完全控制對象復(fù)制的狀態(tài)
[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:以上內(nèi)容主要來自The Ruby Way
用Ruby復(fù)制一個(gè)對象(object)也許沒有你想像的那么容易. 今天我google了半天, 做個(gè)總結(jié)吧.
先從最簡單的開始, b = a 是復(fù)制嗎? 看代碼說話:
>> a= [0,[1,2]]
>> b=a
>> b[0]=88
>> b[1][0]=99
>> b
=> [88, [99, 2]]
>> a
=> [88, [99, 2]]
從上面代碼發(fā)現(xiàn), 一但修改b, 原來的a也同時(shí)被改變了. 甚至:
>> b.equal?(a)
=> true
原來b跟a根本就是同一個(gè)object, 只是馬甲不一樣罷了. 所以b = a不是復(fù)制.
那 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]]
情況似乎有所好轉(zhuǎn), 在修改b后, a還是有一部分被修改了.(0沒有變,但原來的1變成了99).
所以dup有時(shí)候是復(fù)制(如在Array只有一級時(shí)), 但有時(shí)不是復(fù)制哦.
再來一個(gè), 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復(fù)制, 只針對object的第一級屬性.
汗, 難道在Ruby中沒有辦法復(fù)制對像嗎? 也不完全是, 看這個(gè):
>> 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沒有被改變!!! 似乎終于成功找到復(fù)制的辦法了!!!
為什么要加"似乎"呢? 因?yàn)橛行﹐bject是不能被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
更完善的復(fù)制方案可以考慮給ruby增加一個(gè)deep clone功能, 可以參考以下鏈接:
http://d.hatena.ne.jp/pegacorn/20070417/1176817721
轉(zhuǎn)載于:https://www.cnblogs.com/qinyan20/p/9674004.html
總結(jié)
以上是生活随笔為你收集整理的ruby中的复制 dup clone的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于数组的题
- 下一篇: 互联网分布式架构技术概述