ruby复制对象的方法(dup 和 clone)
2013-08-26 16:08
447 查看
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 http://www.artima.com/forums/flat.jsp?forum=123&thread=40913
相关文章推荐
- [置顶] ruby复制对象的方法(dup 和 clone)
- js object对象赋值bug和对象复制clone方法
- java中equals和==之间的区别?clone方法的作用,及其为什么要使用clone方法?如何使用clone复制对象?以及深克隆浅克隆
- java的clone()方法和Java Serializable复制新对象,而不影响原来对象
- 对象的复制:浅复制(clone()方法的使用)+深复制
- php之clone 复制对象以及__clone魔术方法
- 【PHP】对象的复制(拷贝)与__clone()方法
- js object对象赋值bug和对象复制clone方法
- Ruby中如何复制对象 (deep clone)(转载)
- php 对象复制(克隆)clone()
- 工具方法补充,复制非空属性对象,可用于通用数据更新
- Java中clone方法以及深复制和浅复制
- Effective Java - 对于所有对象都通用的方法 - 谨慎地覆盖 clone
- 兼容值类型的JavaScript对象Clone方法javascript
- Object 对象方法学习之(1)—— 使用 Object.assign 复制对象、合并对象
- Java编程中实现Cloneable接口,让类的对象可以复制
- Object.assign() 方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
- JavaScript 复制对象与Object.assign方法无法实现深复制
- clone方法完成javascript中数组的复制
- JavaScript深度复制(deep clone)的实现方法