为啥 3.times 需要一个 .each 如果作为参数传递,但直接使用时不需要,如“3.times do xyz end”
Posted
技术标签:
【中文标题】为啥 3.times 需要一个 .each 如果作为参数传递,但直接使用时不需要,如“3.times do xyz end”【英文标题】:Why does 3.times needs a .each if passed as an argument, but not when used directly, as in "3.times do xyz end"为什么 3.times 需要一个 .each 如果作为参数传递,但直接使用时不需要,如“3.times do xyz end” 【发布时间】:2015-05-23 16:13:10 【问题描述】:这是简单的版本,可以按预期工作
[15] pry(main)> def iter
[15] pry(main)* 3.times do
[15] pry(main)* puts "Hello"
[15] pry(main)* end
[15] pry(main)* end
=> nil
[16] pry(main)> iter
Hello
Hello
Hello
=> 3
但是当我将 Enumerator 作为参数传递时,它需要一个 .each
:
作品:
[17] pry(main)> def iter(enumerator)
[17] pry(main)* enumerator.each do # <-------- Here
[17] pry(main)* puts "Hello"
[17] pry(main)* end
[17] pry(main)* end
=> nil
[18] pry(main)> iter(3.times)
Hello
Hello
Hello
=> 3
不起作用:
[13] pry(main)> def iter(enumerator)
[13] pry(main)* enumerator do # <-------- Here
[13] pry(main)* puts "Hello"
[13] pry(main)* end
[13] pry(main)* end
=> nil
[14] pry(main)> iter(3.times)
NoMethodError: undefined method `enumerator' for main:Object
from (pry):8:in `iter'
我可能是错的,但看起来 Ruby 对“3.times”也就是句法糖进行了特殊处理。是这种情况,还是我错了,这种行为可以从第一原则中预期/推断出来?
顺便说一句,这也有效,这让我怀疑它只是语法糖。
[19] pry(main)> def iter
[19] pry(main)* 3.times.each do
[19] pry(main)* puts "Hello"
[19] pry(main)* end
[19] pry(main)* end
=> nil
[20] pry(main)> iter
Hello
Hello
Hello
=> 3
[21] pry(main)>
【问题讨论】:
【参考方案1】:不是语法糖。由于 Ruby 1.9 的重复方法被构建成这样:
如果有障碍,请让步。 如果没有块,则返回一个枚举器(通过调用类似return to_enum(__method__) unless block_given?
的东西)
小例子:
loop
# => #<Enumerator: main:loop>
【讨论】:
【参考方案2】:3.times
被调用并且该调用的结果(而不是可调用函数)被传递给iter
函数。如果times
在没有块的情况下被调用,它会返回迭代器。迭代器本身不占用块,但您可以在其上调用each
。
【讨论】:
Toms,看起来 3.times 返回一个枚举器:[21] pry(main)> 3.times.class
=> Enumerator
[22] pry(main)> 3.times
=> #<Enumerator: ...>
@vijucat,是的,但是当你调用times
with 一个块时,它不会返回一个枚举器,而是调用这个块指定的次数。这种行为在 ruby stdlib 中很常见
documentation 很清楚:“如果没有给出块,则返回一个枚举器。”以上是关于为啥 3.times 需要一个 .each 如果作为参数传递,但直接使用时不需要,如“3.times do xyz end”的主要内容,如果未能解决你的问题,请参考以下文章
使用 for_each 提升 sub_range;为啥我得到一个常量引用?