为什么Ruby使用yield?

时间:2013-01-14 00:14:36

标签: ruby

我是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本身似乎疯狂,神奇,神秘。毕竟,它会转到呼叫的起源并在呼叫后立即抓住一个阻止。这看起来很古怪和不自然,我不知道这个功能在另一种语言中有任何平行。

那么与yield的交易是什么?

3 个答案:

答案 0 :(得分:14)

产量是语法糖

这个收益率的例子:

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

选择您喜欢的语法并随之疯狂。

答案 1 :(得分:6)

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

答案 2 :(得分:4)

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