2012-01-01 5 views
6

클래스의 객체가 있고 dup으로 복제하려고합니다. 인스턴스 변수 중 하나는 배열이며 참조하는 것처럼 보입니다. 나는 dup이 실제로 중복을 만들었다 고 생각했다. dup는 참조하지, 완전히 새로운 변수를 생성하기 때문에,인스턴스 변수가 여전히 'dup'이후에 참조됩니다.

irb(main):094:0> class G 
irb(main):095:1> attr_accessor :iv 
irb(main):096:1> def initialize 
irb(main):097:2> @iv = [1,2,3] 
irb(main):098:2> end 
irb(main):099:1> end 
=> nil 

irb(main):100:0> a=G.new 
=> #<G:0x27331f8 @iv=[1, 2, 3]> 

irb(main):101:0> b=a.dup 
=> #<G:0x20e4730 @iv=[1, 2, 3]> 

irb(main):103:0> b.iv<<4 
=> [1, 2, 3, 4] 
irb(main):104:0> a 
=> #<G:0x27331f8 @iv=[1, 2, 3, 4] 

내가 a가 변경되지 기대 :

여기 내 IRB 세션입니다.

[1,2,3]G::initialize의 스칼라로 바꾼다면 dup은이를 참조하지 않습니다.

답변

6

dup crates a shallow copy; 인스턴스 변수가 참조하는 오브젝트는 복사되지 않습니다.

정식 (예 : Really Easy) 딥 카피 해킹은 마샬링/언 마샬링이며 실제 사용 사례에서는 작동 할 수도 있고 작동하지 않을 수도 있습니다 (단순화 된 예라고 가정). 그렇지 않은 경우 또는 마샬링이 비효율적 인 경우 initialize_copy 경로가 더 좋은 옵션입니다. 이 같은 배열을 참조하는 두 개의 개체가 있도록

pry(main)> a = G.new 
=> #<G:0x9285628 @iv=[1, 2, 3]> 
pry(main)> b = a.dup 
=> #<G:0x92510a8 @iv=[1, 2, 3]> 
pry(main)> a.iv.__id__ 
=> 76819210 
pry(main)> b.iv.__id__ 
=> 76819210 
pry(main)> b = Marshal::load(Marshal.dump(a)) 
=> #<G:0x9153c3c @iv=[1, 2, 3]> 
pry(main)> a.__id__ 
=> 76819220 
pry(main)> b.__id__ 
=> 76193310 
7

dupclone의 디폴트 구현은, 얕은 복사본을 만듭니다.

class G 
    attr_accessor :iv 
    def initialize_copy(source) 
    super 
    @iv = source.iv.dup 
    end 
end 

그런 다음 두 객체가 서로 다른 두 배열을 참조합니다 : 당신이 원하는 동작을 얻으려면, 당신은 ( dupclone에 의해 호출)를 initialize_copy 함수를 정의해야한다. 배열 그들에 가변 객체가있는 경우, 당신은 배열에서도 깊고 dup 각 개체를 이동 할 수 있습니다 :

def initialize_copy(source) 
    super 
    @iv = source.iv.collect &:dup 
end 
0

재정 dup 또는 clone 방법 :

def dup 
    Marshal::load(Marshal.dump(self)) 
    end