@SergioTulentsev хороший момент

от вопрос уже есть ответ здесь:

Странное, неожиданное поведение (исчезновение / изменение значений) при использовании значения по умолчанию для хэша, например Hash.new ([]) 4 ответа

Я работаю через Ruby Koans, чтобы лучше понять Ruby и TDD. Я добрался до линии 93 в кодеabout_hashes.rb и это смущает меня, как это будет переложено в конструктор по умолчанию вместо хеш-значения. Просто из любопытства я попытался использовать то же самое со строкой в ​​качестве параметра конструктора, и это дало аналогичный результат.

Теперь мой вопрос: почему, какой бы ключ я ни использовал, извлекается один и тот же объект и как бы я помещал новый объект в массив по определенному ключу в хэше метода test_default_value_is_the_same_object?

def test_default_value_is_the_same_object
    hash = Hash.new([])

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

    assert_equal ["uno", "dos"], hash[:one] #why not ["uno"]?
    assert_equal ["uno", "dos"], hash[:two] #why not ["dos"]?
    assert_equal ["uno", "dos"], hash[:three] #why not []?

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

def test_default_value_with_block
    hash = Hash.new {|hash, key| hash[key] = [] }

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

    assert_equal ["uno"], hash[:one]
    assert_equal ["dos"], hash[:two]
    assert_equal [], hash[:three]
end
 Sergio Tulentsev11 окт. 2017 г., 22:53
 Martijn Pieters♦27 нояб. 2017 г., 13:02
@marmeladze:ruby-koans является метатегом, пожалуйста, не создавайте такие теги, мы сожгли тег по причине, см.Burninate Project Euler
 Scott11 окт. 2017 г., 23:01
@SergioTulentsev Я спрашиваю, почему массив в хэше [: one] является таким же массивом в хэше [: two]
 Sergio Tulentsev11 окт. 2017 г., 22:51
«как бы я поместил новый объект в массив hash [: one]» - а? как вы делаете выше.hash[:one] << "uno", После того,hash[:one] будем имеют"uno", Или ты спрашивал что-то еще?

Ответы на вопрос(2)

Вы создали новыйHash сArray как аккумулятор, когда ключа нет так

hash = Hash.new([]) 
hash[:one] << "uno" 
hash[:one] == ["uno"] #=> true

но

hash[:two] << "dos" 
(hash[:one] == hash[:two]) && (hash[:two] == ["uno","dos"]) #=> true
hash[:three] == ["uno","dos"] #=> true

потому что["uno","dos"] это исходный массив, созданный сHash а такжеhash[:non_existant_key] указывает на это.

Примечание: ключи не были добавленыhash в этом случае. Это было бы похоже на

 a = []
 hash = {}
 hash.fetch(:one,a) << 'uno'
 hash.fetch(:two,a) << 'dos'
 hash.fetch(:three, a) 
 #=> ['uno','dos']
 hash
 #=> {}

Чтобы решить эту проблему, вы можете использовать этот синтаксис, как указано в вашем втором тесте

hash = Hash.new {|h,k| h[k] = [] } 

Это означает, что каждый новый ключ создает новыйArray как его значение, а не повторное использование того жеArray снова и снова

Это проблема сHash.new(obj) синтаксис, когдаobj изменчивый объект

 engineersmnky11 окт. 2017 г., 23:02
@SergioTulentsev хороший момент
 Sergio Tulentsev11 окт. 2017 г., 22:58
Важно отметить, что при выполненииhash[:one] << "uno"вы не добавляете новые записи в хеш (и, следовательно, значение по умолчанию при отсутствии ключа - это то, что всегда возвращается)
Решение Вопроса

test_default_value_is_the_same_object есть, чтобы показать вам, что, когда вы проситеhash[:some_value_that_doesnt_exist_yet]по умолчанию вы возвращаете заданное вами значение по умолчанию -тот же объект каждый раз. Изменяя этот объект, вы изменяете его для каждого несуществующего ключа. Изменениеhash[:one] также модифицируетhash[:two].

test_default_value_with_block показывает построение хэша с использованием блока, который будет использоваться для предоставления нового значения для каждого ключа. Когда вы делаете это так, значения дляhash[:one] а такжеhash[:two] различны.

 Scott11 окт. 2017 г., 23:13
Спасибо, я полностью отошел от клавиш, даже ничего не назначено. Я попробовал это и напечатал значение, и это работало, как я ожидал. Очень четкий ответ.

Ваш ответ на вопрос