Неправильный вывод метода Hash # keys - PullRequest
10 голосов
/ 05 июля 2019

При определенных условиях Hash#keys работает некорректно в Ruby до версии 2.4

Демонстрационный код:

h = { a: 1, b: 2, c: 3 }
h.each do |k, v|
    h.delete(:a)
    p h
    p h.keys
    break
end

Выход Ruby 2.3.8:

{:b=>2, :c=>3}
[:b]

Вывод Ruby 2.5.1:

{:b=>2, :c=>3}
[:b, :c]

Я согласен, что неправильно изменять хеш при итерации.Но я не видел связи между модификацией хэша и методом рабочих ключей.

Почему это происходит?

1 Ответ

7 голосов
/ 05 июля 2019

Интересный вопрос.Это еще не ответ, но он слишком длинный для комментария и может помочь другим ответить на вопрос.

Какие рубины затронуты?

Я создал GitHub хранилище с очень простой спецификацией:

describe Hash do
  it "should always know which keys are left" do
    h = { a: 1, b: 2, c: 3 }
    h.each do |k, v|
      h.delete :a
      expect(h.keys).to eq [:b, :c]
    end
  end
end

enter image description here Благодаря Travis легко увидеть, в каких версиях Ruby есть эта ошибка:

  • Ruby 2.1
  • Ruby 2.2
  • Ruby 2.3

Когда появилась ошибка?

Когдабыла ли исправлена ​​ошибка?

Я просто потратил час, используя git bisect и make install, чтобы обнаружить, что ошибка была исправлена ​​в этом коммите (75775157) .

Представляем улучшение таблицы от Владимира Макарова.

[Feature # 12142] Смотрите головуСтр. c для улучшения деталей.

Вы можете увидеть всю историю кода здесь: https://github.com/vnmakarov/ruby/tree/hash_tables_with_open_addressing

Это улучшение обсуждается на https://bugs.ruby -lang.org / questions/ 12142 со многими людьми, особенно с Юрой Соколовым.

  • st.c: улучшение st_table.

  • include / ruby ​​/ st.h: то же самое.

  • internal.h, numeric.c, hash.c (rb_dbl_long_hash): извлечь функцию.

  • ext /-test- / st / foreach / foreach.c: поймать это изменение.

git-svn-id: svn + ssh: //ci.ruby-lang.org/ruby/ trunk @ 56650 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Это было подтверждено @Vovan, который обнаружил этот коммит за 1 минуту до того, как я это сделал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...