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)的更多相关文章

  1. CorelDRAW中六种复制对象的方法详解

    复制可保证对象的大小一致,复制也是所有操作中最基本的操作.CorelDRAW软件中支持多种复制对象的操作,本教程将详解CorelDRAW中六种复制对象的方法. 方法一 选择复制对象,点击编辑→复制,再 ...

  2. [置顶] Ruby,Scala和JavaScript中的函数式编程(一)

    函数式编程(英语:Functional programming)或者函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象.函数编程语言最重要的 ...

  3. Python3基础 内置函数 dir 查询对象的方法列表

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  4. [置顶] ruby变量详解(收集+整理)

    ruby的变量有局部变量,全局变量,实例变量,类变量,常量. 1.局部变量 局部变量以一个小写字母开头或下划线开头 局部变量有局部作用域限制(比如一个block内),它的作用域起始于声明处,结束于该声 ...

  5. [置顶] MyEclipse下安装插件方法(properties文件编辑器Propedit为例)

    网上流传了很多安装插件的方法.在这里我只讲解一种方法. 因为我认为这种方法有以下两个优点:第一.简单,方便安装:第二.对于自己安装的插件易于管理. 我的myeclipse版本号为10.5,操作系统为w ...

  6. [置顶] javascript-基于对象or面向对象?

    最近完成了javascript的初级学习,在这个学习的视频中,我特别注意了两个词,解释性语言和对象,javascript按照我的理解,应该是种解释性语言,他有关于面向对象的思想的体现,但是,他和vb一 ...

  7. [置顶] Oracle学习路线与方法

    还没有整理好.... 1.学习路线 Oracle官方文档:2 Day DBA-->2 Day+Performance Tuning Guide--->Administrator's Gui ...

  8. [置顶] kubernetes资源对象--Label

    概念 Label机制是K8S中一个重要设计,通过Label进行对象弱关联,灵活地分类和选择不同服务或业务,让用户根据自己特定的组织结构以松耦合方式进行服务部署. Label是一对KV,对用户而言非常有 ...

  9. [置顶] kubernetes资源对象--ResourceQuotas

    概念 Resource Quotas(资源配额,简称quota)是对namespace进行资源配额,限制资源使用的一种策略. K8S是一个多用户架构,当多用户或者团队共享一个K8S系统时,SA使用qu ...

随机推荐

  1. 通过java类文件识别JDK编译版本

    类文件中第5,6,7,8四个字节是jDK版本号信息,其中5,6为小版本号:7,8为大版本号. 大版本号对应JDK版本如下: JDK版本号 7,8字节 JDK8 52(0x34) JDK7 51(0x3 ...

  2. 【czy系列赛】czy的后宫6 && bzoj1044 [HAOI2008]木棍分割

    题目描述 众所周知的是丧尸czy有很多妹子(虽然很多但是质量不容乐观QAQ),今天czy把n个妹子排成一行来检阅.但是czy的妹子的质量实在--所以czy看不下去了.检阅了第i个妹子会增加czy a[ ...

  3. WPF Image触摸移动方法

    1: TouchPoint mPoint = null; 2: double mOffsetX;//水平滚动条当前位置 3: double mOffsetY;//垂直滚动条当前位置 4: bool m ...

  4. Java宝典(三)

    --说说ArrayList,Vector,LinkedList的存储性能和特性. --ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,他们都 ...

  5. dp优化

    入口 A(fzu 1894) 普通的单调队列,trick是进队判断的符号选取(>=wa , >ac). B(poj 2823) 没什么好说的 ,坑爹poj g++,tle ;c++,ac. ...

  6. java.lang.IllegalStateException at org.apache.catalina.connector.ResponseFacade

    2012-10-4 19:50:37 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for se ...

  7. 删除list中指定值的元素

    public class ListRemoveAll { public static void main(String[] args) {  // TODO Auto-generated method ...

  8. python学习之路-1 python简介及安装方法

    python简介 一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年发明,第一个公开发行版发行于1991年. 目前最新版本为3.5.1,发布于2015年12月07日 ...

  9. python之路-随笔 python处理excel文件

    小罗问我怎么从excel中读取数据,然后我百了一番,做下记录 以下代码来源于:http://www.cnblogs.com/lhj588/archive/2012/01/06/2314181.html ...

  10. 将字符串变成大写----C++实现

    虽然这个题目很简单,但是也是会范很多错误的,平时你肯定知道,但是在编程的时候就是容易犯傻,而且八匹马都拽不回来... 看来还是要多写写代码..不废话了. 直接贴代码.. #include<ios ...