范尼是德鲁伊

matthew的技术博客

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

  今天在写程序时,发现有两个测试单独运行通过,但一起运行时第二个测试老挂。不用说,产生了依赖了么,找了半天,找到这么两句。

line_string = @@digital_lines[item][line_number]
...
line_string.insert(1,"  ")

  在irb中测试了一下,原来line_string只是一个指针呀,直接就把原始数据给修改了,这不就是鼎鼎大名的深浅拷贝么,汗~~~

  没办法,在Google上面搜了一下,使用了Object中的dup方法,该方法类似于clone方法,返回一个相同值的全新对象,完成深拷贝,参考如下:

ruby-1.8.7-p330 :010 > a = "123"
 => "123" 
ruby-1.8.7-p330 :011 > b = a.dup
 => "123" 
ruby-1.8.7-p330 :012 > a.object_id
 => 2149191580 
ruby-1.8.7-p330 :013 > b.object_id
 => 2149174920 

  可以看出,a和b时两个不同的对象,当然也就不存在相互影响的情况了。

  大功告成了么?No, no, no. 好戏还没有结束,各位看官请往下看  

ruby-1.8.7-p330 :062 > a = [["abc"]]
 => [["abc"]] 
ruby-1.8.7-p330 :063 > b = a.dup
 => [["abc"]] 
ruby-1.8.7-p330 :064 > a.object_id
 => 2149153820 
ruby-1.8.7-p330 :065 > b.object_id
 => 2149144160 
ruby-1.8.7-p330 :066 > a[0][0] = 1
 => 1 
ruby-1.8.7-p330 :067 > a
 => [[1]] 
ruby-1.8.7-p330 :068 > b
 => [[1]]

  虽然调用了dup方法产生了不同的对象,但还是出现了浅拷贝的情况(当a[0][0]=1时,b的值也变了)。同样的情况还出现在Hash和我们自定义的类中。

  想一想我们在C++和Java中时如何解决这个问题的?聪明的你一定想到了吧,既然系统自带的不给力,咱就自己写一个吧。实际上,已经有牛人写好了,我们直接用就行了,嘿嘿~~

  参考如下:http://www.artima.com/forums/flat.jsp?forum=123&thread=40913

  

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

  还等什么,赶紧Command+C走吧~~~

PS:前文提到了dup和clone差不多,那Object中的dup和clone的区别是什么呢?

答案在这里,需要饭强哦(fan qiang是敏感词。。。)。

  

posted on 2011-10-06 00:13  范尼是德鲁伊  阅读(826)  评论(0编辑  收藏  举报