是否保证了Ruby哈希值的顺序? [英] Is order of a Ruby hash literal guaranteed?

查看:107
本文介绍了是否保证了Ruby哈希值的顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Ruby从v1.9开始,在循环散列时支持确定性顺序;

这是否适用于文字,即< $ 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


another comment


$ 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
是有保证的。


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 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, which Hash 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 that Hash#values has the same order as Hash#keys, Hash#each_value and Hash#each_key has the same order as those, and Hash#each_pair and Hash#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.6 Hash 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 as h = { }; 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆