如果您首先了解产量的工作原理可能会有所帮助。这是一个例子:
def do_stuff
if block_given?
yield 5
else
5
end
end
result = do_stuff {|x| x * 3 }
puts result
--output:--
15
在do_stuff方法中调用:
do_stuff {|x| x * 3 }
..该块就像一个函数,它被传递给方法 do_stuff。在 do_stuff 内部,yield 调用该函数并传递指定的参数——在本例中为 5。
需要注意的一些重要事项:
产量称为在方法内部
当你调用一个方法时,你可以向该方法传递一个块
Yield 用于调用该块。
好的,现在我们来看看您的评论问题:
是不是真的
e = Enumerator.new do |y|
y << 1
y << 2
y << 3
end
完全一样
e = Enumerator.new do #I think you forgot to write .new here
yield 1
yield 2
yield 3
end
在第二个示例中,任何地方都没有方法定义——因此您无法调用yield。错误!因此,这两个例子并不相同。
但是,您可以这样做:
def do_stuff
e = Enumerator.new do
yield 1
yield 2
yield 3
end
end
my_enum = do_stuff {|x| puts x*3}
my_enum.next
--output:--
3
6
9
1.rb:12:in `next': iteration reached an end (StopIteration)
from 1.rb:12:in `<main>'
但这是一个有趣的枚举器,因为它不产生任何值——它只是执行一些代码(恰好打印一些输出),然后结束。该枚举器几乎相当于:
def do_stuff
e = Enumerator.new do
end
end
my_enum = do_stuff
my_enum.next
--output:--
1.rb:7:in `next': iteration reached an end (StopIteration)
from 1.rb:7:in `<main>'
当枚举器无法生成值时,它会引发 StopIteration 异常。因此,在这两种情况下,枚举器都无法生成值。
但我仍然不清楚“yielder”在做什么。它看起来
就像它正在收集所有计算值,以便它可以
稍后当您使用计数器时,请反省它们。如果那是
如果是这样,那么看起来它只适用于“小”
序列......你不会想制作一个存储 50 的枚举器
百万件物品。
不。事实上,您可以创建一个生成无限多个值的枚举器。这是一个例子:
e = Enumerator.new do |y|
val = 1
while true
y << val
val += 1
end
end
puts e.next
puts e.next
puts e.next
--output:--
1
2
3
添加一些调试消息应该很有洞察力:
e = Enumerator.new do |y|
val = 1
while true
puts "in while loop"
y << val
val += 1
end
end
puts e.next
--output:--
in while loop
1
请注意,该消息仅打印一次。所以发生了一些不明显的事情:
e = Enumerator.new do |y|
val = 1
while true
puts "in while loop"
y << val
puts "just executed y << val"
val += 1
end
end
puts e.next
--output:--
in while loop
1
因为消息“justexecute y y << val。因此,枚举器不会连续旋转 while 循环并将所有值插入到 y 中——即使语法与将值推入数组完全相同:arr << val
.
What y << val
真正的意思是:当调用 e.next() 时产生这个值,然后继续执行下一行。如果您在上一个示例中添加另一个 e.next,您将看到以下附加输出:
just executed y << val
in while loop
2
发生的情况是,执行总是在以下情况下停止:y << val
代码中遇到。然后调用 e.next 产生右侧的值,然后在下一行继续执行。
如果 ruby 为 Yielder 语句制定如下语法,可能会更有意义:
y >> val
我们可以将其解释为:在这里停止执行,然后当 e.next 被调用时产生 val。
David Black 建议不要使用y.yield val
语法,相当于y << val
以免读者认为它的作用与yield语句类似。y.yield val
应该解释为:“在这里停止执行,当next被调用时产生val,然后在下一行继续执行。我个人认为语法y << val
脱颖而出超过y.yield val
,因此更容易在代码中发现并轻松识别执行停止的位置。