枚举器:使用两个参数收集方法

时间:2011-08-04 06:53:16

标签: ruby enumerable

我有这段代码:

users = ["foo", "bar"]
users.collect { |item, value = []| value << {:name => item} }.flatten

这就像红宝石中的风一样 - 1.9.2:

=> [{:name=>"foo"}, {:name=>"bar"}]

但这在ruby-1.8.7中不起作用,因为它不喜欢收集两个参数:

SyntaxError: compile error
(irb):2: syntax error, unexpected '=', expecting '|'
users.collect { |item, value = []| value << {:name => item} }.flatten

Reading the documentation这是真的,collect不期望两个参数,但它在ruby 1.9.2中工作。我错过了什么,我的Array / Enumerable是以某种奇怪的方式修补的,还是文档错了?

2 个答案:

答案 0 :(得分:5)

我觉得你错过了什么。这就是你想要做的,它适用于1.9和1.8:

users.collect { |i| { :name => i } }

答案 1 :(得分:2)

1.8.7并没有抱怨阻止获取两个参数,它抱怨你试图为第二个参数提供默认值。这样:

users.collect { |item, value| value << {:name => item} }.flatten

在1.8.7中解析正常,但当然,它在运行时会失败,因为valuenil

1.9允许块参数的默认值(见下文)。

所以不,文档没有错,你只是以一种在1.9.2中工作的奇怪方式使用collect,因为它允许块参数的默认值。

无论如何,你对collect的使用有点复杂,可能没有做到你认为它正在做的事情,你应该听Casper并做一个简单的collect

users.collect { |item| { :name => item } }

但是,如果你有<<的东西并想要使用它,无论如何,你可以在1.8.7和1.9.2中使用inject

users.inject([ ]) { |value, item| value << { :name => item } }

但这是毫无意义的复杂性。


你引起了我的好奇心,所以我去了Ruby解析器文件以获得权威参考。也许毫无意义的忙碌工作,但“无意义”和“坏”是不同的事情。

1.9.2-p180 parse.y有以下几点:

block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
                | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
                | f_arg ',' f_block_optarg opt_f_block_arg
                /* ... */
f_block_optarg  : f_block_opt
f_block_opt     : tIDENTIFIER '=' primary_value

如果你稍微追踪它,你会发现block_param规则用于这样的事情:

{ |eggs| ... }
{ |two_cent, stamp| ... }
{ |where_is, pancakes = 'house'| ... }

以及do / end表单。然后从block_param跟踪到f_block_opt,您将看到语法明确允许的默认值。

OTOH,1.8.7-p248 parse.y有这个:

opt_block_var : none
              | '|' /* none */ '|'
              | tOROP
              | '|' block_var '|'

block_var中没有任何内容允许块参数的默认值。 tOROP只是允许这两种形式:

{ | | pancakes }    # '|' /* none */ '|'
{ ||  pancakes }    # tOROP, the logical "or" operator: ||