是否保证了Ruby哈希值的顺序? [英] Is order of a Ruby hash literal guaranteed?
问题描述
这是否适用于文字,即< $ c>总是在b之前产生一个?
我对Ruby 2.1(MRI)做了一个快速实验,事实上它是一致的,在所有Ruby实现上工作的语言?
这个可以指定的,即一些被认为是Ruby语言规范的东西:
ISO规范没有提及 Hash
排序:它的编写方式使得所有现有的Ruby实现都自动符合它,而不必更改,即它被写为描述性当前的Ruby实现,而不是规定的。在编写规范时,这些实现包括MRI,YARV,Rubinius,JRuby,IronRuby,MagLev,MacRuby,XRuby,Ruby.NET,Cardinal,tinyrb,RubyGoLightly,SmallRuby,BlueRuby等。特别令人感兴趣的是MRI(仅 实现了1.8)和YARV( only 实现了1.9(当时)),这意味着规范只能指定行为通常为1.8和1.9,其中 Hash
排序不是。
RubySpec项目被开发人员抛弃令人沮丧的是,红宝石核心开发人员和YARV开发人员从未意识到这一点。但是,它(隐含地)指定<$ c
$ b
<$ c $> Hash 文字从左至右排列: code> new_hash(1 => 2,4 => 8,2 => 4).keys.should == [1,42]
这是 Hash#keys
的规范,但是,其他specs测试 Hash#values
的顺序与 Hash#keys
相同, Hash#each_value
和 Hash#each_key
与它们的顺序相同, Hash#each_pair
和 Hash#each
也具有相同的顺序。
我找不到 YARV测试套件,它指定保存顺序。事实上,我根本找不到任何关于在测试套件中订购的东西,完全相反:根据订购,测试很大程度上避免 !
>在9.5.3.6 <$ c $部分中,Flanagan / matz book kinda-sorta隐式指定了 Hash
c>哈希迭代器。首先,它使用与文档相同的表达方式:
然而,在Ruby 1.9中,散列元素按其插入顺序迭代[ ...
但是,它会继续:
在这些例子中,它 实际上使用的是文字:
h = {:a => 1, :b => 2,:c => 3}
#each()迭代器迭代[key,value]对
h.each {| pair |打印对}#打印[:a,1] [:b,2] [:c,3]
#它也适用于两个块参数
h.each do |键,值|
print#{key}:#{value}#打印a:1 b:2 c:3
结束
#对键或值或两者进行迭代
h.each_key {| k |打印k}#打印abc
h.each_value {| v |打印v}#打印123
h.each_pair {| k,v |打印k,v}#打印a1b2c3。像每个
h = {a:1,b:2}
与h = {}相同; h [:a] = 1; h [:b] = 2
$ p
$ b不幸的是,那是不正确的:
module HashASETWithLogging
def [] =(key,value)
puts[] =用[#{key.inspect}] = #{value.inspect}
super
end
end
class Hash
prepend HashASETWithLogging
end
h = {a:1,b:2}
#什么都不打印
h = {}; h [:a] = 1;用[:a] = 1调用h [:b] = 2
#[] =时调用[:b] = 2
$ c $因此,根据你如何解读书中的这一行,并根据规范是如何判断这本书,是的,排序文字 是有保证的。Ruby, since v1.9, supports a deterministic order when looping through a hash; entries added first will be returned first.
Does this apply to literals, ie will
{ a: 1, b: 2 }
always yield a before b?I did a quick experiment with Ruby 2.1 (MRI) and it was in fact consistent, but to what extent is this guaranteed by the language to work on all Ruby implementations?
解决方案There are couple of locations where this could be specified, i.e. a couple of things that are considered "The Ruby Language Specification":
- the ISO Ruby Language Specification
- the RubySpec project
- the YARV testsuite
- The Ruby Programming Language book by matz and David Flanagan
The ISO spec doesn't say anything about
Hash
ordering: it was written in such a way that all existing Ruby implementations are automatically compliant with it, without having to change, i.e. it was written to be descriptive of current Ruby implementations, not prescriptive. At the time the spec was written, those implementations included MRI, YARV, Rubinius, JRuby, IronRuby, MagLev, MacRuby, XRuby, Ruby.NET, Cardinal, tinyrb, RubyGoLightly, SmallRuby, BlueRuby, and others. Of particular interest are MRI (which only implements 1.8) and YARV (which only implements 1.9 (at the time)), which means that the spec can only specify behavior which is common to 1.8 and 1.9, whichHash
ordering is not.The RubySpec project was abandoned by its developers out of frustration that the ruby-core developers and YARV developers never recognized it. It does, however, (implicitly) specify that
Hash
literals are ordered left-to-right:new_hash(1 => 2, 4 => 8, 2 => 4).keys.should == [1, 4, 2]
That's the spec for
Hash#keys
, however, the other specs test thatHash#values
has the same order asHash#keys
,Hash#each_value
andHash#each_key
has the same order as those, andHash#each_pair
andHash#each
have the same order as well.I couldn't find anything in the YARV testsuite that specifies that ordering is preserved. In fact, I couldn't find anything at all about ordering in that testsuite, quite the opposite: the tests go to great length to avoid depending on ordering!
The Flanagan/matz book kinda-sorta implicitly specifies
Hash
literal ordering in section 9.5.3.6Hash
iterators. First, it uses much the same formulation as the docs:In Ruby 1.9, however, hash elements are iterated in their insertion order, […]
But then it goes on:
[…], and that is the order shown in the following examples:
And in those examples, it actually uses a literal:
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
In his comment, @mu is too short mentioned that
h = { a: 1, b: 2 }
is the same ash = { }; h[:a] = 1; h[:b] = 2
and in another comment that
nothing else would make any sense
Unfortunately, that is not true:
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
So, depending on how you interpret that line from the book and depending on how "specification-ish" you judge that book, yes, ordering of literals is guaranteed.
这篇关于是否保证了Ruby哈希值的顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!