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. 《java入门第一季》之UDP协议下的网络编程小案例

    需求,一台电脑发送数据,其他电脑都可以收到该数据.使用广播地址. 发送端: import java.io.BufferedReader; import java.io.IOException; imp ...

  2. Android项目-高考作文功能简介(一)

    前言 :  开发安卓也已2年多了近3年了, 在自己刚入行的时候就有自己独立开发一个App的想法. 后来自己做了<<高考作文>>这一App. 后面续续断断的维护者. 也因为功能简 ...

  3. android binder理解

    Android中的Parcel是什么  Parcel,翻译过来是"打包"的意思.打包干什么呢?是为了序列化.     如果要在进程之间传递一个整数,很简单,直接传就是行了:如果要传 ...

  4. 《java入门第一季》之正则表达式常见规则

    正则表达式规则不用记住,只是知道是做什么用的即可.常见规则如下: A:字符 x 字符 x.举例:'a'表示字符a \\ 反斜线字符. \n 新行(换行)符 ('\u000A') (\\n来表示换行) ...

  5. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api

    Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...

  6. 《java入门第一季》之面向对象静态内部类和非静态内部类的区别

    很感谢在内部类章节,"开心阳"先生给与的建议.使用静态内部类.这里就简单说一下静态内部类的使用. package com.devin; public class MyMain{ p ...

  7. AngularJS进阶(四)ANGULAR.JS实现下拉菜单单选

    ANGULAR.JS: NG-SELECT AND NG-OPTIONS PS:其实看英文文档比看中文文档更容易理解,前提是你的英语基础还可以.英文文档对于知识点讲述简明扼要,通俗易懂,而有些中文文档 ...

  8. Learning ROS for Robotics Programming Second Edition学习笔记(五) indigo computer vision

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  9. 求二叉树深度和copy二叉树

    // operatorTree.cpp // 对树的操作 #include <iostream> #include <cstdio> // 二叉树表示法 typedef str ...

  10. 【Android 应用开发】Android中的回调Callback

    回调就是外部设置一个方法给一个对象, 这个对象可以执行外部设置的方法, 通常这个方法是定义在接口中的抽象方法, 外部设置的时候直接设置这个接口对象即可. 例如给安卓添加按钮点击事件, 我们创建了OnC ...