`
jy503160
  • 浏览: 20122 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

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

    博客分类:
  • ruby
 
阅读更多

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

分享到:
评论

相关推荐

    文件描述符的复制:dup()和dup2()示例代码

    在Linux系统编程中,文件描述符(File Descriptor)是操作系统用来标识进程打开的文件或设备的一个非负整数值。...在实际开发中,根据具体需求选择合适的方法复制文件描述符,能够使程序设计更加高效和简洁。

    UNIX编程中的dup和dup2说明

    UNIX 编程中的 dup 和 dup2 函数是两个非常有用的系统调用,它们的作用都是用来复制一个文件的描述符。它们经常用来重定向进程的 stdin、stdout 和 stderr。 dup 函数的原型为 `int dup(int oldfd)`, 它可以复制一...

    dup_dup2介绍

    在Linux操作系统中,`dup`和`dup2`是两个重要的系统调用,它们与文件描述符管理和进程间通信紧密相关。本文将详细介绍这两个函数的工作原理、使用场景以及如何用C语言实现它们。 首先,我们来看`dup`系统调用。`dup...

    Ruby-Ruby中的GoF设计模式实现

    Ruby支持对象的克隆,`Object#clone`或`Object#dup`方法可以实现原型模式。 6. **适配器模式**:将一个类的接口转换成客户希望的另一个接口。Ruby的鸭子类型特性使得适配器模式尤为自然,只需确保对象响应所需的...

    ruby api

    1. Object:所有Ruby对象的基类,包含了一些通用的方法,如`object_id`用于获取对象的唯一标识,`==`进行对象的比较,`clone`和`dup`用于创建对象的副本。 2. String:处理文本字符串的类,提供了丰富的字符串操作...

    Dup-Pack:基于CRIS的FPGA装箱方法.pdf

    FPGA硬件技术是计算机硬件开发领域的重要分支,尤其在专用集成电路设计与应用方面具有广泛的作用。...随着FPGA技术在各个领域应用的不断扩展,Dup-Pack这种创新的装箱方法将会得到更为广泛的关注和应用。

    详细介绍dup2函数用法,一看必懂.。。。

    其中,`dup` 和 `dup2` 函数在处理文件描述符时非常有用。本文将深入探讨这两个函数的用途及其工作原理,特别是 `dup2` 的使用场景。 #### 二、文件描述符的概念 在Linux或Unix系统中,每个进程都会有一系列的文件...

    DUP414中文驱动

    总的来说,DUP414中文驱动是确保DUP-414设备在中文操作系统环境中正常运行的关键软件,而提供的压缩包文件则包含了安装和测试驱动所需的所有内容。用户只需按照正确的步骤操作,就能让设备充分发挥其功能,处理各种...

    dup源代码dup

    dup函数在系统编写程序的用法 及源代码

    dup 补丁 2.2汉化版

    1. **dup2_help.chm**:这是补丁的帮助文件,以CHM( Compiled HTML Help)格式存在,通常包含了详细的操作指南和使用方法,用户可以通过查阅此文件了解如何使用补丁以及各项功能的具体用途。 2. **DisasmEngineDLL...

    ruby数组

    - **复制数组**:`clone`或`dup`可以创建数组的副本,避免原数组被修改。 ### 数组迭代 Ruby提供了许多迭代方法来处理数组中的每个元素,如`each`、`map`、`each_with_index`等。例如: ```ruby arr.each { |...

    java虚拟机指令dup详解

    在 Java 中,dup 指令的使用非常频繁,例如在创建异常对象时,需要使用 dup 指令来复制对象的引用,以便将其传递给实例初始化方法。在创建集合对象时,dup 指令也可以用于复制集合的引用,以便将其传递给相关的方法...

    dUP v2.17 Beta 23

    8. `汉化说明.txt`:详细解释了汉化过程和需要注意的事项,对用户理解汉化版软件的特性和使用方法非常有帮助。 9. `icons`:这是一个文件夹,可能包含软件的各种图标资源。 10. `chiptunes`:可能是一组用于软件界面...

    DUP 2.1 补丁编写工具

    在软件开发和维护过程中,补丁是修复程序错误、提升性能或增强功能的关键手段,DUP 2.1 提供了强大的功能来简化这一过程。 偏移量补丁主要针对二进制文件中的特定地址进行修改,通过指定原始值和目标值,可以在不...

    vb.net dup通信

    vb.net dup通信,含打洞技术,很有用,提供给大家学习。

    dup2.25内存补丁制作工具

    总结起来,"dup2.25内存补丁制作工具"凭借其强大的功能和人性化的界面设计,成为了IT从业者进行软件调试和优化的首选工具。无论是对于专业开发者还是业余爱好者,都能从中找到适用的解决方案。通过深入理解和熟练...

    ruby学习笔记

    `dup` 和 `clone` 都可以用来复制字符串,但它们之间存在细微的区别。 #### 5. 转换 - `capitalize`: 将字符串的第一个字符转换为大写,其余字符转换为小写。 - `upcase`: 将整个字符串转换为大写。 - `downcase`:...

    dup2.19.beta

    dup2函数在Linux系统编程中扮演着重要的角色,它是用于重定向或复制文件描述符的核心函数。"dup2.19.beta"可能是指一个实验性的或者测试版本的库或者工具,其中包含了对dup2函数的改进或特定实现。在这个版本中,...

    Ruby中Hash哈希结构的基本操作方法小结

    要避免这种情况,可以使用`clone`或`dup`方法创建副本: ```ruby h3 = h2 # 浅复制,改变h3会影响h2 h4 = h2.clone # 深复制,改变h4不会影响h2 ``` 至于Hash的排序,由于键和值可能为任意类型,排序并不直接。Ruby...

Global site tag (gtag.js) - Google Analytics