ruby复制对象的方法(dup 和 clone)

[ruby]  view plain copy
  1. Ruby内置的方法Object#clone和Object#dup可以用来copy一个对象,两者区别是dup只复制对象的内容,而clone还复制与对象相关联的内容,如singleton method  
  2. [ruby] view plaincopyprint?  
  3. s = "cat"    
  4. def s.upcase    
  5.     "CaT"    
  6. end    
  7. s_dup = s.dup    
  8. s_clone = s.clone    
  9. s_dup.upcase        #=> "CAT"  (singleton method not copied)    
  10. s_clone.upcase      #=> "CaT" (uses singleton method)    
  11.   
  12. dup和clone都是浅复制Shallow Copy,也就是只能复制接受方的内容,而如果接受方包含到其他对象的引用,那么就只是会复制这些引用了。  
  13. [ruby] view plaincopyprint?  
  14. arr1 = [ 1, "flipper", 3 ]    
  15. arr2 = arr1.dup    
  16. arr2[2] = 99    
  17. arr2[1][2] = 'a'    
  18. arr1                #=> [1, "flapper", 3]    
  19. arr2                #=> [1, "flapper", 99]    
  20. 可以看到arr1中有一个到String对象的引用,从而arr2也复制了这个引用,当arr2中修改这个引用时,arr1中的也会发生变化。  
  21. 如果要进行深复制Deep Copy,可以聪明的采用Marshal模块  
  22. [ruby] view plaincopyprint?  
  23. arr1 = [ 1, "flipper", 3 ]    
  24. arr2 = Marshal.load(Marshal.dump(arr1))    
  25. arr2[2] = 99    
  26. arr2[1][2] = 'a'    
  27. arr1                #=> [1, "flipper", 3]    
  28. arr2                #=> [1, "flapper", 99]    
  29. 现在就会发现arr2中对String对象的修改不会导致arr1的变化了,因为深了。。。不过Marshal模块并不能把所有的对象都序列化  
  30. class中还有一个与对象复制相关的特殊方法initialize_copy,这个方法会在信息复制完成后执行,看下面这个示例  
  31. [ruby] view plaincopyprint?  
  32. class Document    
  33.     attr_accessor :title:text    
  34.     attr_reader :timestamp    
  35.     
  36.     def initialize(title, text)    
  37.         @title@text = title, text    
  38.         @timestamp = Time.now    
  39.     end    
  40. end    
  41.     
  42. doc1 = Document.new("Random Stuff""Haha")    
  43. sleep 10    
  44. doc2 = doc1.clone    
  45.     
  46. doc1.timestamp == doc2.timestamp        #=> true    
  47. 也就是两个对象是完全一样的,构造函数initialize被跳过了,所以两个对象的时间戮timestamp是相同的。如果要采用执行复制操作时的时间,我们可以通过给Document类添加initialize_copy方法来实现。initialize_copy让程序员能完全控制对象复制的状态  
  48. [ruby] view plaincopyprint?  
  49. class Document    #Reopen the class    
  50.     def initialize_copy(other)    
  51.         @timestamp = Time.now    
  52.     end    
  53. end    
  54.     
  55. doc3 = Document.new("More Stuff""Haha")    
  56. sleep 10    
  57. doc4 = doc1.clone    
  58.     
  59. doc3.timestamp == doc4.timestamp        #=> false    
  60. 再次感慨Ruby的魅力。。。  
  61. PS:以上内容主要来自The Ruby Way  
  62.   
  63. 用Ruby复制一个对象(object)也许没有你想像的那么容易. 今天我google了半天, 做个总结吧.  
  64. 先从最简单的开始, b = a 是复制吗? 看代码说话:  
  65. >> a= [0,[1,2]]  
  66. >> b=a  
  67. >> b[0]=88  
  68. >> b[1][0]=99  
  69. >> b    
  70. => [88, [99, 2]]  
  71. >> a    
  72. => [88, [99, 2]]  
  73. 从上面代码发现, 一但修改b, 原来的a也同时被改变了. 甚至:  
  74.   
  75. >> b.equal?(a)  
  76. => true  
  77. 原来b跟a根本就是同一个object, 只是马甲不一样罢了. 所以b = a不是复制.  
  78. 那 b = a.dup呢?? 还是看代码:  
  79. >> a= [0,[1,2]]  
  80. >> b=a.dup  
  81. >> b[0]=88  
  82. >> b[1][0]=99  
  83. >> b  
  84. => [88, [99, 2]]  
  85. >> a  
  86. => [0, [99, 2]]  
  87. 情况似乎有所好转, 在修改b后, a还是有一部分被修改了.(0没有变,但原来的1变成了99).  
  88. 所以dup有时候是复制(如在Array只有一级时), 但有时不是复制哦.  
  89. 再来一个, b = a.clone呢? 上代码:  
  90. >> a= [0,[1,2]]  
  91. >> b=a.clone  
  92. >> b[0]=88  
  93. >> b[1][0]=99  
  94. >> b  
  95. => [88, [99, 2]]  
  96. >> a  
  97. => [0, [99, 2]]  
  98. 情况几乎跟dup一模一样. 所以clone也不一定可以相信哦!   
  99. 原来ruby中的dup和clone都是shallow复制, 只针对object的第一级属性.   
  100. 汗, 难道在Ruby中没有办法复制对像吗? 也不完全是, 看这个:  
  101. >> a= [0,[1,2]]  
  102. >> b=Marshal.load(Marshal.dump(a))  
  103. >> b[0]=88  
  104. >> b[1][0]=99  
  105. >> b  
  106. => [88, [99, 2]]  
  107. >> a= [0,[1,2]]  
  108. => [0, [1, 2]]  
  109. 修改b后a没有被改变!!! 似乎终于成功找到复制的办法了!!!  
  110. 为什么要加"似乎"呢? 因为有些object是不能被Marshal.dump的.如:  
  111. >> t=Object.new  
  112. >> def t.test; puts ‘test’ end  
  113. >> Marshal.dump(t)  
  114. TypeError: singleton can’t be dumped  
  115.     from (irb):59:in `dump’  
  116.     from (irb):59  
  117. 更完善的复制方案可以考虑给ruby增加一个deep clone功能, 可以参考以下链接:  
  118. http://d.hatena.ne.jp/pegacorn/20070417/1176817721  
  119. http://www.artima.com/forums/flat.jsp?forum=123&thread=40913  

转自 http://blog.csdn.net/dazhi_100/article/details/17021741
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值