Ruby中如何复制对象 (deep clone)

用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中如何复制对象 (deep clone)(转载)的更多相关文章

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

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

  2. CorelDRAW中如何复制对象属性详解

    复制对象属性是一种比较特殊.重要的复制方法,它可以方便而快捷地将指定对象中的轮廓笔.轮廓色.填充和文本属性通过复制的方法应用到所选对象中.本教程将详解CorelDRAW中如何复制对象属性. Corel ...

  3. JavaScript 中的对象深度复制(Object Deep Clone)

    JavaScript中并没有直接提供对象复制(Object Clone)的方法. JavaScript中的赋值,其实并不是复制对象,而是类似`c/c++`中的引用(或指针),因此下面的代码中改变对象b ...

  4. 深入探讨JavaScript如何实现深度复制(deep clone)

    在代码复用模式里面有一种叫做“复制属性模式”(copying properties pattern).谈到代码复用的时候,很有可能想到的是代码的继承性(inheritance),但重要的是要记住其最终 ...

  5. ruby中的可调用对象--proc和lamdba

    ruby中将块转变成对象的三种方法 ruby中的大部分东西都是对象,但是块不是.那么,如果你想存下来一个块,方便以后使用,你就需要一个对象.ruby中有三种方法,把块转换成可以利用的对象. Proc. ...

  6. JavaScript 复制对象【Object.assign方法无法实现深复制】

    在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...

  7. ruby中symbol

    Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字. 创建一个 Symb ...

  8. ruby中的方法查找

    ruby中的方法调用都是 对象.方法 的形式,那么对象如何找到这个方法呢? 首先必须了解祖先链的概念,祖先链就是从一个类开始,到它的父类,再到父类的父类...一直到最终的起点(ruby中是BasicO ...

  9. ruby中的self

    self,自己,在ruby中表示当前对象或默认对象.程序执行的任一时刻,有且仅有一个self. 1.谁成为self,在什么位置成为self? 要知道哪个对象是self,就必须知道当前的上下文.上下文主 ...

随机推荐

  1. Mybatis执行CachingExecutor(六)

    前面几篇博客我们介绍了Excutor及抽象类BaseExecutor和实现类SimpleExecutor.BatchExecutor和ReuseExecutor: 博客列表: Mybatis执行Exe ...

  2. Java学习从菜鸟变大鸟之三 多线程中Thread 和Runnable的区别与运用

    多线程机制是java中的一个特点,掌握它对后面的知识的理解至关重要,是java工程师的必备知识,多线程指在单个程序中可以运行多个不同的线程执行的不同的任务,线程是一个程序内部的顺序控制流.进程是静态的 ...

  3. iOS编程中的音频知识(一):文件格式和数据格式,哦!天哪

    要明白实际上每个音频文件都有2各部分组成:它的文件格式(或称之为音频容器),和它的数据格式(或称之为音频编码). 文件格式(audio containers)描述文件自身的格式.实际内部的音频数据可以 ...

  4. TCP三次握手及其背后的缺陷

    概述 总结一下TCP中3次握手过程,以及其原生的缺陷 引起的SYN Flood的介绍 [1]TCP三次握手 [2]SYN Flood 1.TCP连接建立--三次握手 几个概念: [1]seq:序号,占 ...

  5. Android使用SimpleAdapter

    SimpleAdapter的使用步骤如下: 声明ListView,并进行初始化操作 准备数据集,一般用list来实现,当然也可以使用数组 为listview适配simpleadapter 如下代码: ...

  6. [WinForm]最小化到系统托盘,右键退出

    1.拉出一个notifyIcon1到用户界面,也可以NEW一个 2.拉出一个ContextMenuStrip控件,命名为mymenu,集合中增加退出 3.notifyIcon1的属性ContextMe ...

  7. Linux进程实践(3) --进程终止与exec函数族

    进程的几种终止方式 (1)正常退出 从main函数返回[return] 调用exit 调用_exit/_Exit (2)异常退出 调用abort   产生SIGABOUT信号 由信号终止  Ctrl+ ...

  8. E-JSON数据传输标准

    简介 E-JSON的设计目标是使业务系统向浏览器端传递的JSON数据保持一致,容易被理解和处理,并兼顾传输的数据量.E-JSON依托于http协议(rfc2616)与JSON数据交换格式(rfc462 ...

  9. python 去掉 pyc

    python 去掉 .pyc 在开发的机器上(Ubuntu),python自动生成的pyc文件太影响心情,把下面的语句添加到 /etc/profile中: # do not produce .pyc ...

  10. 018-继承-OC笔记

    学习目标 1.[掌握]Xcode开发文档 2.[掌握]static关键字 3.[掌握]self关键字 4.[掌握]继承 5.[掌握]NSObject 6.[掌握]访问修饰符 7.[掌握]私有实例变量和 ...