10 votes

Sortie erronée de la méthode Hash#keys

Sous certaines conditions Hash#keys ne fonctionne pas correctement dans Ruby avant la version 2.4

Code démo :

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 sortie :

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

Sortie Ruby 2.5.1 :

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

Je suis d'accord pour dire qu'il n'est pas bon de modifier le hash lors de l'itération. Mais je n'ai pas vu la relation entre la modification du hash et la méthode work keys.

Pourquoi cela se produit-il ?

7voto

Eric Duminil Points 38857

Question intéressante. Ce n'est pas encore une réponse, mais c'est trop long pour un commentaire et cela pourrait aider d'autres personnes à répondre à la question.

Quels sont les rubis concernés ?

J'ai créé un compte GitHub dépôt avec une spécification très simple :

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 Merci à Travis il est facile de voir quelles versions de Ruby présentent ce bogue :

  • Ruby 2.1
  • Ruby 2.2
  • Ruby 2.3

Quand le bug est-il apparu ?

Quand le bug a-t-il été corrigé ?

Je viens de passer une heure à utiliser git bisect y make install afin de constater que le bogue a été corrigé dans cette version. commit (75775157) .

Introduire l'amélioration de la table par Vladimir Makarov .

[Fonctionnalité #12142] Voir l'en-tête de st.c pour les détails de l'amélioration.

Vous pouvez voir toute l'histoire du code ici : https://github.com/vnmakarov/ruby/tree/hash_tables_with_open_addressing

Cette amélioration est examinée à l'adresse suivante https://bugs.ruby-lang.org/issues/12142 avec de nombreuses personnes, surtout avec Yura Sokolov.

  • st.c : améliorer st_table.

  • include/ruby/st.h : idem.

  • internal.h, numeric.c, hash.c (rb_dbl_long_hash) : extraire une fonction.

  • ext/-test-/st/foreach/foreach.c : rattraper ce changement.

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

Cela a été confirmé par @Vovan, qui a trouvé ce commit 1 minute avant moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X