帮助理解 Ruby 中的产量和枚举器
如果有人能帮助我理解在枚举器中使用 Yielder 与仅在枚举器中调用 Yielder 之间的区别,我将不胜感激。
“接地气的 Rubyist”表明人们不会“从区块中屈服”,但没有准确解释发生了什么。
谢谢
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
如果有人能帮助我理解在枚举器中使用 Yielder 与仅在枚举器中调用 Yielder 之间的区别,我将不胜感激。
“接地气的 Rubyist”表明人们不会“从区块中屈服”,但没有准确解释发生了什么。
谢谢
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(3)
如果您首先了解产量的工作原理可能会有所帮助。 下面是一个例子:
在 do_stuff 方法调用中:
..该块就像一个函数,它被传递给 do_stuff 方法。 在 do_stuff 内部,yield 调用函数并传递指定的参数——在本例中为 5.
需要注意的一些重要事项:
yield 在方法内部被调用
当你调用一个方法时,你可以向该方法传递一个块
yield 用于调用块。
好的,现在我们来看看您的评论问题:
,因为任何地方都没有方法定义——所以你不能调用yield。 错误! 因此,这两个例子并不相同。
但是,您可以这样做:
但这是一个有趣的枚举器,因为它不会产生任何值 - 它只是执行一些代码(恰好打印一些输出),然后结束。 该枚举器几乎相当于:
当枚举器无法生成值时,它会引发 StopIteration 异常。 因此,在这两种情况下,枚举器都无法生成值。
不。事实上,您可以创建一个生成无限多个值的枚举器。 这是一个示例:
添加一些调试消息应该很有洞察力:
请注意,该消息仅打印一次。 所以发生了一些不明显的事情:
因为消息“justexecute y << val”没有出现在输出中,这意味着执行必须在
y << 行停止。 值。 因此,枚举器不会连续旋转 while 循环并将所有值插入到 y 中——即使语法与将值推入数组完全相同:
arr << 值。
什么
y << val
的真正含义是:当调用 e.next() 时产生这个值,然后继续执行下一行。 如果在前面的示例中添加另一个 e.next,您将看到以下附加输出:发生的情况是,当
y <<< 时执行总是停止。 代码中遇到val
。 然后调用 e.next 产生右侧的值,然后在下一行继续执行。如果 ruby 为 Yielder 语句制定这样的语法,可能会更有意义:
我们可以将其解释为:在此处停止执行,然后在调用 e.next 时生成 val。
David Black 建议不要使用 y.yield val 语法,该语法相当于 y << 最有价值的读者认为它的工作原理与yield 语句类似。
y.yield val
应该解释为:“在这里停止执行,当next调用product val时,则在下一行继续执行。我个人认为语法y < 比 y.yield val
更突出,因此更容易在代码中发现并轻松识别执行停止的位置。It might help if you first understand how yield works. Here is an example:
In the the do_stuff method call:
..the block is like a function, and it is passed to the method do_stuff. Inside do_stuff, yield calls the function and passes the specified arguments--in this case 5.
Some important things to note:
yield is called inside a method
When you call a method, you can pass a block to the method
yield is used to call the block.
Okay, now let's look at your comment question:
In the second example, there is no method definition anywhere--so you can't call yield. Error! Therefore, the two examples are not the same.
However, you could do this:
But that is a funny enumerator because it doesn't produce any values--it just executes some code(which happens to print some output), then ends. That enumerator is almost equivalent to:
When an enumerator cannot produce a value, it raises a StopIteration exception. So in both cases, the enumerator couldn't produce a value.
No. In fact, you can create an enumerator that produces an infinite number of values. Here is an example:
Adding some debugging messages should prove insightful:
Note that the message only printed once. So something is going on that is not obvious:
Because the message "just executed y << val" does not show up in the output, that means execution must have halted on the line
y << val
. Therefore, the enumerator did not continuously spin the while loop and insert all the values into y--even though the syntax is exactly the same as pushing values into an array:arr << val
.What
y << val
really means is: when e.next() is called produce this value, then continue execution on the next line. If you add another e.next to the previous example, you will see this additional output:What's happening is that execution always halts when
y << val
is encountered in the code. Then calling e.next produces the value on the right side, then execution continues on the next line.It would probably have made more sense if ruby had made the syntax for the yielder statement like this:
And we could interpret that as meaning: halt execution here, then when e.next is called produce val.
David Black recommends not using the
y.yield val
syntax, which is equivalent toy << val
lest readers think it works similarly to the yield statement.y.yield val
should be interpreted as: "stop execution here, and when next is called produce val, then continue execution on the next line. Personally, I think that the syntaxy << val
stands out more thany.yield val
, so it is easier to spot in the code and readily identify where execution halts.好吧,除非我遗漏了什么,否则
yield
方法根本不起作用。 尝试一下:这会产生这样的结果:
当他说(第 304 页)“你不要这样做”时,他的意思并不是“这不是最好的方法”。 他的意思是,“那是行不通的。”
编辑:但是,您可以这样显式调用yield:
如果您发现
yield
比<<
更明确或更清晰,那么就这样做。第二次编辑:看看大卫的原始帖子和乔格的更新答案,我认为这个问题最初存在混乱。 Jorg 认为 David 是在问
Enumerator::Yielder#yield
和Enumerator::Yielder::<<
之间的区别,但 David 不确定是什么>The Well Grounded Rubyist 的意思是“不要写yield 1
等”。 我的回答适用于有关The Well Grounded Rubyist的问题。 (当我今天回顾这个帖子时,鉴于其他更新,我的答案看起来很奇怪。)Well, unless I'm missing something, the method with
yield
simply doesn't work. Try it:Which produces this:
When he says (page 304) "you don't do this," he doesn't mean "it's not the best way to do it." He means, "that won't work."
Edit: You can, however, call yield explicitly this way:
If you find saying
yield
more explicit or clearer than<<
, then do it that way.Second edit: Looking at David's original post and Jorg's updated answer, I think that there was a confusion originally about the question. Jorg thought David was asking about the difference between
Enumerator::Yielder#yield
andEnumerator::Yielder::<<
, but David wasn't sure what The Well Grounded Rubyist means when it says "don't writeyield 1
etc." My answer applies to the question about The Well Grounded Rubyist. (When I looked this thread back over today, my answer looked odd in the light of other updates.)Enumerator::Yielder#yield
方法和Enumerator::Yielder::<<
方法完全相同。 事实上,它们是别名。因此,您使用这两者中的哪一个,是 100% 个人喜好,就像
Enumerable#collect
和Enumerable#map
或Enumerable#inject
和Enumerable#reduce
。The
Enumerator::Yielder#yield
method and theEnumerator::Yielder::<<
method are exactly the same. In fact, they are aliases.So, which one of those two you use, is 100% personal preference, just like
Enumerable#collect
andEnumerable#map
orEnumerable#inject
andEnumerable#reduce
.