- 浏览: 335181 次
- 性别:
- 来自: 北京
文章分类
最新评论
先来个老段子:
自从深发展银行推出那条知性的广告语“只想与你深发展”后,银行业内人士又自编出了更知性的姊妹篇:“光大是不行的”
正题:研究一下ruby中深拷贝(deep clone)的问题。
1.=
ruby里拷贝对象的最简单方法,下面来看一下效果:
b修改后,a也跟着修改了,并且a和b的object_id一样,就是同一个对象嘛~
2.dup和clone(dup和clone差不多,但是还是有一些区别的)
b和a是不同对象,并且改变b后a不改变。这是我们想要的。但是别高兴太早,看下面例子:
显然,问题又有了,改变s2后s1也跟着改变了。同样的陷阱也发生在Array和Hash里,看下面代码:
在第一次给arr_dup[0]复值的时候arr没有改变,而第二次改变arr_dup[1][0]的时候arr也跟着改变了。就是说Array#dup只拷贝了一层,还不够深入呀..同样Hash也是,看下面代码:
3.用序列化实现深拷贝
情况似乎好多了。但是还有一个问题,就是Marshal只能序列化一般对象,数组哈希,高级一些的对象不能序列化(IO,Proc,singleton等)
下面是两个deep clone的实现(via:http://www.artima.com/forums/flat.jsp?forum=123&thread=40913)
更复杂的(via:http://d.hatena.ne.jp/pegacorn/20070417/1176817721)...
Something about dup and clone
1.ruby字面量(Fixnum,true,false,nil,Symbol)不可以调用dup和clone方法,会报TypeError。
2.对对象的state(taint,frozen)的改变:dup会把frozen的对象unfrozen,clone不会。
3.对单体方法的拷贝:clone会连同单体方法一起拷贝,dup不会。
引用
自从深发展银行推出那条知性的广告语“只想与你深发展”后,银行业内人士又自编出了更知性的姊妹篇:“光大是不行的”
正题:研究一下ruby中深拷贝(deep clone)的问题。
1.=
ruby里拷贝对象的最简单方法,下面来看一下效果:
irb(main):002:0> a = "Hooopo" => "Hooopo" irb(main):003:0> b = a => "Hooopo" irb(main):004:0> b.object_id => 23424840 irb(main):005:0> a.object_id => 23424840 irb(main):006:0> b.gsub!("o","-") => "H---p-" irb(main):007:0> p a "H---p-" => nil irb(main):008:0> p b "H---p-" => nil
b修改后,a也跟着修改了,并且a和b的object_id一样,就是同一个对象嘛~
2.dup和clone(dup和clone差不多,但是还是有一些区别的)
irb(main):001:0> a = "Hooopo" => "Hooopo" irb(main):002:0> b = a.dup => "Hooopo" irb(main):003:0> a.object_id => 23428740 irb(main):004:0> b.object_id => 23425010 irb(main):005:0> b.gsub!("o","-") => "H---p-" irb(main):006:0> p b "H---p-" => nil irb(main):007:0> p a "Hooopo" => nil irb(main):008:0>
b和a是不同对象,并且改变b后a不改变。这是我们想要的。但是别高兴太早,看下面例子:
class Klass attr_accessor :str end s1 = Klass.new s1.str = "Hooopo" p s1 s2 = s1.dup p s2 s2.str.gsub!("o","-") p s1 p s2 #results #<Klass:0x2d2cd30 @str="Hooopo"> #<Klass:0x2d2cc7c @str="Hooopo"> #<Klass:0x2d2cd30 @str="H---p-"> #<Klass:0x2d2cc7c @str="H---p-">
显然,问题又有了,改变s2后s1也跟着改变了。同样的陷阱也发生在Array和Hash里,看下面代码:
irb(main):008:0> arr = [1,[1,1]] => [1, [1, 1]] irb(main):009:0> arr_dup = arr.dup => [1, [1, 1]] irb(main):010:0> arr_dup[0] = 2 => 2 irb(main):011:0> arr => [1, [1, 1]] irb(main):012:0> arr_dup[1][0] = 2 => 2 irb(main):013:0> arr => [1, [2, 1]]
在第一次给arr_dup[0]复值的时候arr没有改变,而第二次改变arr_dup[1][0]的时候arr也跟着改变了。就是说Array#dup只拷贝了一层,还不够深入呀..同样Hash也是,看下面代码:
irb(main):001:0> hash = {:key => {:key => "value"}} => {:key=>{:key=>"value"}} irb(main):002:0> hash_dup = hash.dup => {:key=>{:key=>"value"}} irb(main):003:0> hash_dup[:key][:key] = "value_changed" => "value_changed" irb(main):004:0> hash_dup => {:key=>{:key=>"value_changed"}} irb(main):005:0> hash => {:key=>{:key=>"value_changed"}}
3.用序列化实现深拷贝
irb(main):014:0> arr = [1,[1,1]] => [1, [1, 1]] irb(main):015:0> arr_dump = Marshal.load(Marshal.dump(arr)) => [1, [1, 1]] irb(main):016:0> arr_dump.object_id => 22807940 irb(main):017:0> arr.object_id => 22850200 irb(main):018:0> arr_dump[1][1] = 2 => 2 irb(main):019:0> arr_dump => [1, [1, 2]] irb(main):020:0> arr => [1, [1, 1]]
irb(main):012:0> hash = {:key => {:key => "value"}} => {:key=>{:key=>"value"}} irb(main):013:0> hash_dump = Marshal.load(Marshal.dump(hash)) => {:key=>{:key=>"value"}} irb(main):014:0> hash.object_id => 22790990 irb(main):015:0> hash_dump.object_id => 22755440 irb(main):016:0> hash_dump[:key][:key] = "value not changed" => "value not changed" irb(main):017:0> hash => {:key=>{:key=>"value"}} irb(main):018:0> hash_dump => {:key=>{:key=>"value not changed"}}
情况似乎好多了。但是还有一个问题,就是Marshal只能序列化一般对象,数组哈希,高级一些的对象不能序列化(IO,Proc,singleton等)
下面是两个deep clone的实现(via:http://www.artima.com/forums/flat.jsp?forum=123&thread=40913)
class Object def deep_clone Marshal::load(Marshal.dump(self)) end end
class Object def dclone case self when Fixnum,Bignum,Float,NilClass,FalseClass, TrueClass,Continuation klone = self when Hash klone = self.clone self.each{|k,v| klone[k] = v.dclone} when Array klone = self.clone klone.clear self.each{|v| klone << v.dclone} else klone = self.clone end klone.instance_variables.each {|v| klone.instance_variable_set(v, klone.instance_variable_get(v).dclone) } klone end end
更复杂的(via:http://d.hatena.ne.jp/pegacorn/20070417/1176817721)...
class Object def deep_clone _deep_clone({}) end protected def _deep_clone(cloning_map) return cloning_map[self] if cloning_map.key? self cloning_obj = clone cloning_map[self] = cloning_obj cloning_obj.instance_variables.each do |var| val = cloning_obj.instance_variable_get(var) begin val = val._deep_clone(cloning_map) rescue TypeError next end cloning_obj.instance_variable_set(var, val) end cloning_map.delete(self) end end class Array protected def _deep_clone(cloning_map) return cloning_map[self] if cloning_map.key? self cloning_obj = super cloning_map[self] = cloning_obj cloning_obj.map! do |val| begin val = val._deep_clone(cloning_map) rescue TypeError # end val end cloning_map.delete(self) end end class Hash protected def _deep_clone(cloning_map) return cloning_map[self] if cloning_map.key? self cloning_obj = super cloning_map[self] = cloning_obj pairs = cloning_obj.to_a cloning_obj.clear pairs.each do |pair| pair.map! do |val| begin val = val._deep_clone(cloning_map) rescue TypeError # end val end cloning_obj[pair[0]] = pair[1] end cloning_map.delete(self) end end
Something about dup and clone
1.ruby字面量(Fixnum,true,false,nil,Symbol)不可以调用dup和clone方法,会报TypeError。
2.对对象的state(taint,frozen)的改变:dup会把frozen的对象unfrozen,clone不会。
irb(main):019:0> o = Object.new => #<Object:0x2b7855c> irb(main):020:0> o.taint => #<Object:0x2b7855c> irb(main):021:0> o.freeze => #<Object:0x2b7855c> irb(main):024:0> [o.frozen?,o.tainted?] => [true, true] irb(main):025:0> o_clone = o.clone => #<Object:0x2b44c0c> irb(main):026:0> [o_clone.frozen?,o_clone.tainted?] => [true, true] irb(main):027:0> o_dup = o.dup => #<Object:0x2b32e6c> irb(main):028:0> [o_dup.frozen?,o_dup.tainted?] => [false, true]
3.对单体方法的拷贝:clone会连同单体方法一起拷贝,dup不会。
irb(main):029:0> o = Object.new => #<Object:0x2b256a4> irb(main):030:0> def o.say irb(main):031:1> puts "Hello,Hooopo" irb(main):032:1> end => nil irb(main):033:0> o_dup = o.dup => #<Object:0x296acec> irb(main):035:0> o_clone = o.clone => #<Object:0x2dba194> irb(main):037:0> o_dup.say NoMethodError: undefined method `say' for #<Object:0x296acec> from (irb):37 from :0 irb(main):038:0> o_clone.say Hello,Hooopo
评论
5 楼
orcl_zhang
2009-12-10
Hooopo分析真是透彻。看下api。
Produces a shallow copy of obj—the instance variables of obj are copied, but not the objects they reference. dup copies the tainted state of obj. See also the discussion under Object#clone. In general, clone and dup may have different semantics in descendent classes. While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendent object to create the new instance.
分析下。
1,Produces a shallow copy of obj—the instance variables of obj are copied, but not the objects they reference.
借用下Hooopo的代码。希望不要介意。
b对象,存储的"Hooopo",b改变,所以a不会变。
s1,s2虽然是不同的对象,但是对象内储的却是Klass一个实例的地址。所以会改变。
attr数组内存储的是1和[2,1]的地址,所以attr[0]改变不会受影响,而attr[1]则会受影响。
2,While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendent object to create the new instance.
最后这句是关键。clone是在复制对象,包括对象的状态,而dup则是从其派生类创建一个新的实例。所以对于attr=[1, [1, 1]],attr[0]存的是integer,会创建integer类型,attr[1]是一个数组类型,dup只能简单的复制attr[1]中用来保存[1,1]的地址的类的一个新实例。
对于hash,或者更复杂的类,我想原理应该是相同的。
有什么不对的,还希望能指出来。
Produces a shallow copy of obj—the instance variables of obj are copied, but not the objects they reference. dup copies the tainted state of obj. See also the discussion under Object#clone. In general, clone and dup may have different semantics in descendent classes. While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendent object to create the new instance.
分析下。
1,Produces a shallow copy of obj—the instance variables of obj are copied, but not the objects they reference.
借用下Hooopo的代码。希望不要介意。
irb(main):001:0> a = "Hooopo" => "Hooopo" irb(main):002:0> b = a.dup => "Hooopo" irb(main):003:0> a.object_id => 23428740 irb(main):004:0> b.object_id => 23425010 irb(main):005:0> b.gsub!("o","-") => "H---p-" irb(main):006:0> p b "H---p-" => nil irb(main):007:0> p a "Hooopo" => nil irb(main):008:0>
b对象,存储的"Hooopo",b改变,所以a不会变。
class Klass attr_accessor :str end s1 = Klass.new s1.str = "Hooopo" p s1 s2 = s1.dup p s2 s2.str.gsub!("o","-") p s1 p s2 #results #<Klass:0x2d2cd30 @str="Hooopo"> #<Klass:0x2d2cc7c @str="Hooopo"> #<Klass:0x2d2cd30 @str="H---p-"> #<Klass:0x2d2cc7c @str="H---p-">
s1,s2虽然是不同的对象,但是对象内储的却是Klass一个实例的地址。所以会改变。
irb(main):008:0> arr = [1,[1,1]] => [1, [1, 1]] irb(main):009:0> arr_dup = arr.dup => [1, [1, 1]] irb(main):010:0> arr_dup[0] = 2 => 2 irb(main):011:0> arr => [1, [1, 1]] irb(main):012:0> arr_dup[1][0] = 2 => 2 irb(main):013:0> arr => [1, [2, 1]]
attr数组内存储的是1和[2,1]的地址,所以attr[0]改变不会受影响,而attr[1]则会受影响。
2,While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendent object to create the new instance.
最后这句是关键。clone是在复制对象,包括对象的状态,而dup则是从其派生类创建一个新的实例。所以对于attr=[1, [1, 1]],attr[0]存的是integer,会创建integer类型,attr[1]是一个数组类型,dup只能简单的复制attr[1]中用来保存[1,1]的地址的类的一个新实例。
对于hash,或者更复杂的类,我想原理应该是相同的。
有什么不对的,还希望能指出来。
4 楼
night_stalker
2009-06-14
1.8 可以用:
但是 1.9 不能用……
require 'ruby2ruby' module X def x 'x' end end Ruby2Ruby.translate X #=> "module X\n def x\n \"x\"\n end\nend"
但是 1.9 不能用……
3 楼
Hooopo
2009-06-14
http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/8c08df930291a2e9/3cccf36faad55d8c?hl=zh-cn&lnk=gst&q=dump+module#3cccf36faad55d8c
How about the following? The only major disadvantage is that it will be a
little bit slower than using a real Proc:
How about the following? The only major disadvantage is that it will be a
little bit slower than using a real Proc:
require 'delegate' class DumpableProc < DelegateClass(Proc) def initialize(str) eval "@proc = proc { #{str} }" @str = str super(@proc) end def _dump(limit) @str end def self._load(str) self.new(str) end end dp = DumpableProc.new("puts 'foo!'") dp.call() dump_str = Marshal.dump(dp) puts dump_str dp2 = Marshal.load(dump_str) dp2.call()
2 楼
Hooopo
2009-06-14
<div class="quote_title">night_stalker 写道</div>
<div class="quote_div">Array、Hash、实例变量 已经足够表达数据结构了。 data 易 dump,class 不易 dump ……<br><br>现在最想要的是 Binding 和 Proc 的 Marshal.dump, 或者 dump module 也行……</div>
<p><br><span style="font-family: 'times new roman', times;"><span style="font-size: medium;">|I can understand why Thread and the IOs can't be dumped (because there <br>|are underlying operating system structures associated with them), but <br>|can't see why Proc, Continuation and Method couldn't be dumped/loaded ... <br>|although I could see that it might not be possible in the special case <br>|where their bindings included a Thread or an IO of some form. <br>| <br>|Is it just that it's considered too hard to get right (and I'm not saying <br>|it would be easy!) or is there some other reason? <br>Procs, Bindings and Continuations contain references to C stack <br>information which is not portable. Methods have references to C <br>function. All of above information is not portable. <br> matz. </span></span></p>
<p> </p>
<div class="quote_div">Array、Hash、实例变量 已经足够表达数据结构了。 data 易 dump,class 不易 dump ……<br><br>现在最想要的是 Binding 和 Proc 的 Marshal.dump, 或者 dump module 也行……</div>
<p><br><span style="font-family: 'times new roman', times;"><span style="font-size: medium;">|I can understand why Thread and the IOs can't be dumped (because there <br>|are underlying operating system structures associated with them), but <br>|can't see why Proc, Continuation and Method couldn't be dumped/loaded ... <br>|although I could see that it might not be possible in the special case <br>|where their bindings included a Thread or an IO of some form. <br>| <br>|Is it just that it's considered too hard to get right (and I'm not saying <br>|it would be easy!) or is there some other reason? <br>Procs, Bindings and Continuations contain references to C stack <br>information which is not portable. Methods have references to C <br>function. All of above information is not portable. <br> matz. </span></span></p>
<p> </p>
1 楼
night_stalker
2009-06-14
Array、Hash、实例变量 已经足够表达数据结构了。 data 易 dump,class 不易 dump ……
现在最想要的是 Binding 和 Proc 的 Marshal.dump, 或者 dump module 也行……
现在最想要的是 Binding 和 Proc 的 Marshal.dump, 或者 dump module 也行……
发表评论
-
新博客
2012-04-23 20:47 1734https://db-china.org -
Ruby Verbose Warning Mode
2011-10-16 14:48 2051Ruby在很多方面是一个更优雅的Perl,从Perl社区继承了 ... -
Pattern Match In Ruby
2011-10-07 01:17 2006最近看了一些Erlang,模式匹配是个好东西,简单的sum函数 ... -
Draper: View Models for Rails
2011-10-07 01:19 2268Draper是一个Ruby gem,它让Rails model ... -
Active Record batch processing in parallel processes
2011-10-07 01:20 2270Active Record 提供 find_each来分批处理 ... -
最轻量级的Ruby后台任务
2011-08-04 16:47 3860普通情况下ruby调用系统命令行的过程是堵塞的,无论是用sys ... -
test
2011-07-15 19:59 0test -
fiber
2011-06-17 09:37 0挖坑,待填。。 1.用到fiber.alive?、fiber ... -
Identity Map in Rails3.1
2011-06-12 18:29 2737Identity Map是Rails3.1的又 ... -
xx00
2011-06-06 03:40 0https://github.com/ngmoco/cache ... -
挖坑1
2011-06-06 02:17 0cache money 源码 替换memcache为redis ... -
websocket demo
2011-06-04 20:44 2054地址:https://github.com/hooopo/we ... -
ruby GC
2011-06-02 04:24 0http://blog.csdn.net/lijun84/a ... -
reduce method missing call stack with dynamic define method
2011-04-22 22:54 1592method_missing是ruby里面一个非常cool的h ... -
Autocompete with Trie
2011-04-09 04:04 1674像微薄里面用户输入一 ... -
用imagemagick和tesseract-ocr破解简单验证码
2011-04-09 01:31 18926工具:imagemagick + tesseract-ocr ... -
OAuth gem for rails,支持豆瓣,新浪微薄,腾讯微博,搜狐微博,网易微博
2011-03-26 03:13 4480地址:https://github.com/hooopo/oa ... -
用jmeter模拟amf请求进行压力测试
2010-12-16 16:56 30221.获取amf二进制包: 在本地建立proxy,端口为888 ... -
Memoization in Ruby
2010-11-14 11:42 1210这里的Memoization就是将ruby的方法或lambda ... -
整理了一下2008-2010的RubyHeroes博客列表
2010-10-07 02:26 2827Bryan Helmkamp(webrat作者)https:/ ...
相关推荐
深发展与平安银行.doc
【标题】: "深发展与平安银行合并的IT技术整合分析" 【描述】: 这份文档虽然提及的是南昌大众交通公司与江西长运股份公司的资产评估案例,但考虑到标签为"技术",我们可以推测其中可能涉及到银行合并过程中的IT系统...
【平安并购深发展案例分析】 该案例主要涉及的是中国平安集团对深圳发展银行(简称深发展)的并购过程,这是一起在中国金融市场上具有重要意义的并购事件。平安集团,成立于1988年,是中国领先的综合金融服务集团,...
【XXXX年抗通胀理财推介会(深发展).pptx】这份文档是关于2011年深发展银行举办的一场抗通胀理财活动的介绍,重点讨论了如何通过理财策略应对当时的通货膨胀压力。文档中提到的讲师是国家注册黄金分析师何伟锋,他...
深发展银行的这份合同详细规定了保理业务的操作流程、各方权利和责任。 1. **保理业务**:保理是一种金融服务,通过银行收购企业的应收账款,企业可以提前获得资金,同时银行负责应收账款的收回。在合同中,保理...
基于平安并购深发展的案例分析.pptx
[精选]黄金白银延期简介_黄金T+D特点_白银T+D特点_黄金投资历程_深发展银行.pptx
深发展银行开户流程.ppt
深发展银行开户流程.pptx
深发展重庆推广提案.ppt
【深发展重庆推广提案】是华宇广告公司针对深圳发展银行重庆分行提出的一份营销策划方案,旨在通过专业且创新的广告策略推动深发展银行在重庆市场的业务拓展。该提案着重强调了以下几个核心知识点: 1. **专业广告...
科尔尼—深发展银行MoreSlides032905.pptx
深发展银行在调研了众多华东地区的企业后发现,许多中小出口企业与固定的境外买家保持稳定交易,且主要采用赊销方式,尽管账期较长,但收款及时,现金流状况良好。因此,“池融资”产品能针对性地满足这类企业的融资...
"深发展行情看盘软件"是一款专为投资者设计的金融交易工具,主要针对股票、黄金、货币汇率等金融市场,提供实时、全面的数据分析和图表展示功能。这款软件是看盘者进行市场研究和决策的重要助手。 在股市投资中,...
【平安集团并购深发展案例深度解析】 平安集团是中国领先的综合性金融服务集团,成立于1988年,总部位于深圳。该集团拥有全方位的金融业务牌照,包括寿险、产险、养老险、健康险、银行、证券、信托、资产管理以及...