zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    leetcode教程系列——Binary Tree
    《Ranked List Loss for Deep Metric Learning》CVPR 2019
    《Domain Agnostic Learning with Disentangled Representations》ICML 2019
    Pytorch从0开始实现YOLO V3指南 part5——设计输入和输出的流程
    Pytorch从0开始实现YOLO V3指南 part4——置信度阈值和非极大值抑制
    Pytorch从0开始实现YOLO V3指南 part3——实现网络前向传播
    Pytorch从0开始实现YOLO V3指南 part2——搭建网络结构层
    Pytorch从0开始实现YOLO V3指南 part1——理解YOLO的工作
    让我佩服的人生 文章
    win8.1配置cordova+ionic等一系列东西
  • 原文地址:https://www.cnblogs.com/qinyan20/p/9674004.html
Copyright © 2011-2022 走看看