是否保证Ruby哈希文字的顺序?
Ruby,自v1.9起,在循环哈希时支持确定性顺序; 首先添加的条目将首先返回。
这是否适用于文字,即{ a: 1, b: 2 }
总是在b之前产生?
我做了一个Ruby 2.1(MRI)的快速实验,它实际上是一致的,但是语言在多大程度上保证了所有Ruby实现的工作?
可以指定几个位置,即一些被认为是“Ruby语言规范”的东西:
- ISO Ruby语言规范
- RubySpec项目
- YARV测试套件
- 由matz和David Flanagan撰写的Ruby Programming Language一书
ISO规范没有提及任何关于Hash
排序的内容:它是以这样的方式编写的,即所有现有的Ruby实现都自动符合它,而不必更改,即它被编写为描述当前的Ruby实现,而不是规定性的 。 在编写规范时,这些实现包括MRI,YARV,Rubinius,JRuby,IronRuby,MagLev,MacRuby,XRuby,Ruby.NET,Cardinal,tinyrb,RubyGoLight,SmallRuby,BlueRuby等。 特别感兴趣的是MRI( 仅实现1.8)和YARV( 仅实现1.9(当时)),这意味着规范只能指定1.8和1.9共有的行为,而Hash
排序则不然。
RubySpec项目被开发人员抛弃了,因为ruby-core开发人员和YARV开发人员从未认识到它。 但是,它(隐式地) 指定Hash
文字从左到右排序 :
new_hash(1 => 2, 4 => 8, 2 => 4).keys.should == [1, 4, 2]
这是Hash#keys
的规范,然而,其他规格测试Hash#values
与Hash#keys
具有相同的顺序, Hash#each_value
和Hash#each_key
具有与那些相同的顺序,并且Hash#each_pair
和Hash#each
都有同样的顺序。
我在YARV测试套件中找不到任何指定保留排序的东西。 事实上,我在测试套件中找不到任何关于订购的东西,恰恰相反:测试需要很长时间以避免依赖于订购!
Flanagan / matz book kinda-sorta在9.5.3.6节Hash
迭代器中隐式指定了Hash
文字排序。 首先,它使用与文档大致相同的公式:
但是,在Ruby 1.9中,哈希元素按其插入顺序进行迭代,[…]
但接着它继续:
[…],这就是以下示例中显示的顺序:
在这些示例中,它实际上使用了一个文字:
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太短了
h = { a: 1, b: 2 }
与h = { }; h[:a] = 1; h[:b] = 2
相同h = { }; h[:a] = 1; h[:b] = 2
h = { }; h[:a] = 1; h[:b] = 2
并在另一个评论中说
没有别的意义
不幸的是,事实并非如此:
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
所以,根据你如何从书中解释这一行,并根据“规范 – 是什么”来判断那本书,是的,文字的排序是有保证的。
从文档 :
哈希按照插入相应键的顺序枚举其值。