2012-11-11 1 views
2

가능한 중복 :
Ruby method Array#<< not updating the array in hash
Strange ruby behavior when using Hash.new([])Hash.new ([])는 예상대로 작동하지 않습니다

내가 대단한 Koans을하고 있었고, 내가 가서로 따라 서 나는 큰 문제는 발견하지 못했지만, 나는 이것에 비틀 거리며 그것을 이해할 수 없다 :

def test_default_value_is_the_same_object 
     hash = Hash.new([]) 

     hash[:one] << "uno" 
     hash[:two] << "dos" 

     assert_equal ["uno", "dos"], hash[:one] # But I only put "uno" for this key! 
     assert_equal ["uno", "dos"], hash[:two] # But I only put "dos" for this key! 
     assert_equal ["uno", "dos"], hash[:three] # I didn't shove anything for :three! 

     assert_equal true, hash[:one].object_id == hash[:two].object_id 
    end 

모든 테스트가 끝났습니다 (필자가 올바른 어설 션을 작성하는 데 도움이되는 오류를 보았습니다).

마지막 어설 션은 모두 초기화되지 않았으므로 둘 다 기본값이므로 동일한 값을 가져야합니다.

기본 값이으로 변경된 이유를 알지 못합니다. 그게 무슨 일인지 전혀 모르겠습니다.

IRB에서 해봤 던지/어레이가 나를 미치게 만들었다 고 생각했지만 어쩌면 똑같은 결과가 나옵니다.

나는 처음으로 hash[:one] << "uno"{ one: ["uno] }이 될 hash을 암시한다고 생각하지만, { }으로 남습니다.
내가 << 같은데요하지만 단지 push 호출하고

내가 놓친 걸 말해주십시오 = 기호를 사용할 때 새 키는 추가됩니다.

편집 : 당신이 직접 h을 수정

h = Hash.new(0) 
h[:foo] += 1 

작업을 수행 할 때 내가

+1

* * 배열 하나만 있습니다 : 값 ('[]')은 * new 메소드가 호출되기 전에 평가됩니다. 블록을 취하는 "기본 형식"을 시도해보십시오 (블록이 생성되거나 호출 될 때마다 실제 * new * 배열을 생성합니다). 나는 이것이 중복 된 것이라고 확신한다. –

+0

그래, 이것도 몇 번 물어 봤어. :) –

+0

@pst 당신이 정교 할 수 있니? 내가 따르고 있는지 잘 모르겠다. 그래서 SO/Google/Duckduckgo에서 비슷한 질문을 찾지 못했지만 항상 물건을 놓칠 수 있습니다.) –

답변

3

해시에 기본 인수를 사용하면 명시 적으로 설정되지 않은 모든 키에 동일한 개체가 사용됩니다. 즉 배열이 여기에 사용 중이며 Hash.new에 전달 된 배열입니다. 저것의 기록을 위해 아래에보십시오.

>> h = Hash.new([]) 
=> {} 
>> h[:foo] << :bar 
=> [:bar] 
>> h[:bar] << :baz 
=> [:bar, :baz] 
>> h[:foo].object_id 
=> 2177177000 
>> h[:bar].object_id 
=> 2177177000 

이상한 점은 발견 한대로 해시를 조사하면 비어있는 것을 알 수 있습니다!이는 기본 객체 만 수정되었으므로 아직 키가 할당되지 않았기 때문입니다.

다행히 해시에 대한 기본값을 수행하는 또 다른 방법이 있습니다. 대신 기본 블록을 제공 할 수 있습니다

>> h = Hash.new { |h,k| h[k] = [] } 
=> {} 
>> h[:foo] << :bar 
=> [:bar] 
>> h[:bar] << :baz 
=> [:baz] 
>> h[:foo].object_id 
=> 2176949560 
>> h[:bar].object_id 
=> 2176921940 

이 방법을 사용

는 블록 지정되지 않은 키를 사용할 때마다 실행됩니다, 그리고 해시 자체 인수로 키를 제공한다. 블록 내에서 기본값을 지정하면 각 개별 키에 대해 새 개체가 만들어지며 할당이 자동으로 수행됩니다. 이것은 Ruby에서 "Hash of Arrays"를 만드는 관용적 방법이며 일반적으로 기본 인수 방식보다 사용하는 것이 더 안전합니다.

즉, 숫자와 같은 변경 불가능한 값으로 작업하는 경우 Hash.new(0)과 같은 작업은 다시 할당하여 값을 변경하기 때문에 안전합니다. 그러나 나는 머리 속의 개념을 더 적게 유지하기를 원하기 때문에 블록 형태를 독점적으로 사용합니다.

1

루비 1.9.3를 사용하고 있습니다. h[:foo] += 1h[:foo] = h[:foo]+1과 같습니다. h[:foo]0+1입니다.

당신이 h의 기본값 인, []하지만 h의 키에 값이 아닙니다 h[:foo]을 수정

h = Hash.new([]) 
h[:foo] << :bar 

을 수행 할 때. [][:bar]이되면 h의 기본값은 [:bar]이되지만 이는 h[:foo]의 값이 아닙니다.

관련 문제