枚举器:带有两个参数的收集方法

发布于 2024-11-27 23:45:47 字数 725 浏览 1 评论 0 原文

我有这样的代码:

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

这在 ruby​​-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

阅读文档 这是真的,collect 不需要两个参数,但它在 ruby​​ 中工作1.9.2.那么我是否遗漏了一些东西,我的 Array/Enumerable 正在以某种奇怪的方式进行修补,或者文档是否错误?

I have this code:

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

That is working like the wind in ruby-1.9.2:

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

But this does not work in ruby-1.8.7 because it does not like collect getting two parameters:

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

Reading the documentation that's true, collect does not expect two parameters, but it's working in ruby 1.9.2. So am I missing something, my Array/Enumerable is being patched in some weird way or is the documentation wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绮筵 2024-12-04 23:45:47

我认为你错过了一些东西。这就是你想要做的,它在 1.9 和 1.8 中都有效:

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

I think you are missing something. This is what you want to do, and it works in both 1.9 and 1.8:

users.collect { |i| { :name => i } }
那些过往 2024-12-04 23:45:47

1.8.7 并不是抱怨块获取两个参数,而是抱怨您尝试为第二个参数提供默认值。这个:

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

在 1.8.7 中解析得很好,但是,当然,它在运行时会失败,因为 valuenil

1.9 确实允许块参数使用默认值(见下文)。

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

无论如何,您对collect的使用有点复杂,并且可能没有按照您想象的那样做,您应该听Casper并只做一个简单的collect

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

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

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: ||

1.8.7 isn't complaining about the block getting two parameters, it is complaining about your attempt to provide a default value for the second parameter. This:

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

parses fine in 1.8.7 but, of course, it falls over at run time because value is nil.

1.9 does allow default values for block arguments (see below).

So no, the documentation isn't wrong, you're just using collect in a strange way that works in 1.9.2 because it allows default values for block arguments.

Anyway, your using of collect is a bit convoluted and might not be doing quite what you think it is doing, you should listen to Casper and just do a simple collect:

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

But, if you have a thing for << and want to use it no matter what, you could use inject in both 1.8.7 and 1.9.2:

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

That is pointless complexity though.


You piqued my curiosity so I went to the Ruby parser files for an authoritative reference. Pointless busy work perhaps but "pointless" and "bad" are different things.

The 1.9.2-p180 parse.y has these things:

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

If you trace through it a bit, you'll see that the block_param rule is used for things like this:

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

and the do/end form as well. Then trace from block_param down to f_block_opt and you'll see where default values are explicitly allowed by the grammar.

OTOH, The 1.8.7-p248 parse.y has this:

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

There is nothing in block_var that allows default values for block arguments. The tOROP is just there to allow both of these forms:

{ | | pancakes }    # '|' /* none */ '|'
{ ||  pancakes }    # tOROP, the logical "or" operator: ||
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文