15

我是红宝石的新手。我使用了很多允许高阶函数的 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呢?

4

4 回答 4

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

选择您喜欢的语法并随心所欲地使用它。

于 2013-01-14T01:25:42.757 回答
6

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
于 2013-01-14T01:11:58.100 回答
4

一个优点yield是它还允许您使用next(like continue) 和break. 在其他语言中,对于next,您可能必须使用return,而对于break,您可能必须(ab)使用异常。可以说,为这些操作提供内置支持会更好。

于 2013-01-14T00:22:10.303 回答
1

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

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

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

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

于 2015-12-21T05:06:00.080 回答