Ruby 哈希文字的顺序是否有保证?

Is order of a Ruby hash literal guaranteed?

Ruby,从 v1.9 开始,在遍历哈希时支持确定性顺序;先添加的条目将首先返回。

这是否适用于文字,即 { a: 1, b: 2 } 总是在 b 之前产生 a?

我用 Ruby 2.1 (MRI) 做了一个快速实验,它实际上是一致的,但是语言在多大程度上保证这适用于所有 Ruby 实现?

来自documentation

Hashes enumerate their values in the order that the corresponding keys were inserted.

有几个位置可以指定 ,即一些被认为是 "The Ruby Language Specification":

的地方

ISO 规范没有说明 Hash 排序:它的编写方式使得所有现有 Ruby 实现都自动符合它,而无需更改,即它被编写为 描述性 当前 Ruby 实现,而不是 规范性 。在编写规范时,这些实现包括 MRI、YARV、Rubinius、JRuby、IronRuby、MagLev、MacRuby、XRuby、Ruby.NET、Cardinal、tinyrb、RubyGoLightly、SmallRuby、BlueRuby 等。特别感兴趣的是 MRI( 实现 1.8)和 YARV( 实现 1.9(当时)),这意味着规范只能指定 1.8 和 1.9 共有的行为,Hash 排序不是。

RubySpec 项目被其开发人员放弃,因为 ruby-核心开发人员和 YARV 开发人员从未认识到它。但是,它确实(隐含地)specify that Hash literals are ordered left-to-right

new_hash(1 => 2, 4 => 8, 2 => 4).keys.should == [1, 4, 2]

这是 Hash#keys 的规范,但是,其他规范测试 Hash#valuesHash#keysHash#each_valueHash#each_key 具有相同的顺序与那些相同的顺序,Hash#each_pairHash#each也具有相同的顺序。

我在 the YARV testsuite 中找不到任何指定保留顺序的内容。事实上,我 根本 找不到任何关于在那个测试套件中订购的东西,恰恰相反:测试会花很长的时间 避免 取决于在订购!

Flanagan/matz 书有点隐式地指定 Hash 章节 9.5.3.6 Hash 迭代器 中的文字顺序。首先,它使用与文档大致相同的公式:

In Ruby 1.9, however, hash elements are iterated in their insertion order, […]

但接下来会继续:

[…], and that is the order shown in the following examples:

在那些例子中,实际上使用了文字:

h = { :a=>1, :b=>2, :c=>3 }

# The each() iterator iterates [key,value] pairs
h.each {|pair| print pair }    # Prints "[:a, 1][:b, 2][:c, 3]"

# It also works with two block arguments
h.each do |key, value|                
  print "#{key}:#{value} "     # Prints "a:1 b:2 c:3" 
end

# Iterate over keys or values or both
h.each_key {|k| print k }      # Prints "abc"
h.each_value {|v| print v }    # Prints "123"
h.each_pair {|k,v| print k,v } # Prints "a1b2c3". Like each

, @mu is too short中提到

h = { a: 1, b: 2 } is the same as h = { }; h[:a] = 1; h[:b] = 2

并且在

nothing else would make any sense

不幸的是,事实并非如此:

module HashASETWithLogging
  def []=(key, value)
    puts "[]= was called with [#{key.inspect}] = #{value.inspect}"
    super
  end
end

class Hash
  prepend HashASETWithLogging
end

h = { a: 1, b: 2 }
# prints nothing

h = { }; h[:a] = 1; h[:b] = 2
# []= was called with [:a] = 1
# []= was called with [:b] = 2

因此,根据您如何解读书中的那一行以及您如何 "specification-ish" 判断那本书,是的, 保证了文字的顺序。