为什么Ruby使用yield?

我是Ruby的新手。 我使用了很多允许高阶函数的C#和JavaScript,我通常每天使用它们。

Ruby虽然对我来说有点奇怪。 each函数可能如下所示:

 def each @items.each do |item| yield(item) end end items.each { |item| puts item } 

然而Ruby也对高阶函数有一些支持。 以上内容可以改写为:

 def each(proc) @items.each do |item| proc.call item end end items.each -> (item) { puts item } # Or... items.each lambda { |item| puts item } 

甚至:

 def each(&proc) @items.each do |item| proc.call item end end # No difference in syntax. items.each { |item| puts item } 

哪个更与大多数其他语言相提并论,只是几个字符更长。 一切似乎都使用了yield ,而不是明确地传入一个块。

yield本身似乎疯狂,神奇,神秘。 毕竟,它会转到呼叫的起源并在呼叫后立即抓住一个阻止。 这看起来很奇怪和不自然,我不知道这个function在另一种语言中有任何平行。

那么yield多少呢?

Yield将对象传递给方法块

[收益]转到呼叫的起源并在呼叫后立即抓住一个阻止。

并不是的。 yield将参数传递给块; 它不会“抓住一块”或用它做任何事情。 换句话说,这个:

 def foo; yield self; end foo { |x| x.inspect } # => "main" 

这里, yield不会做任何事情,只是将参数传递给传递给foo方法的块。 每个Ruby方法都支持一个可选块 – 除非块实际上是强制性的 – 所以唯一的“魔力”是语言允许传递一个块,即使它没有被明确声明为方法签名的一部分。

更多例子

要查看此隐式签名,请考虑以下事项:

 def foo; puts block_given?; end foo { |x| x.inspect } 

将打印“true”并返回nil ,这是puts方法的预期返回值。

当然,没有yield该块根本不做任何事情。 例如:

 def foo; end foo { |x| x.inspect } # => nil 

产量是Syntax Sugar

这个收益率的例子:

 def do_something_for_each(array) array.each do |el| yield(el) end end 

只是语法糖:

 def do_something_for_each(array, &block) array.each do |el| block.call(el) end end 

选择你喜欢的语法并随之运行。

yield一个优点是它还允许你使用next (如continue )和break 。 在其他语言中,对于next语言,您可能必须使用return ,而对于break ,您可能必须(ab)使用exception。 对这些类型的操作提供内置支持可能更好。

在大多数情况下,使用yield在方法中执行块。

该块直接传递给方法,然后该方法可以使用yield关键字回调该块。

 def a_method(a, b) a + yield(a, b) end a_method(1, 2) {|x, y| (x + y) * 3 } # => 10 

当您回调该块时,您可以为其参数提供值,就像调用方法时一样。 此外,与方法一样,块返回它评估的最后一行代码的结果。