19

目前我正在阅读 David A. Black 的“The Well-Grounded Rubyist”,我停留在 10.9 章(枚举器和可枚举性的下一个维度)。我的问题是关于yield方法的。yield在 Ruby 上下文中这个词的含义是什么?我的母语是俄语,谷歌翻译向我展示了一堆翻译变体,这让我很困惑。其中有一些:给予带来投降放弃),生产同意遵守等等。

UPD:请注意,我试图理解 Enumerator::Yielder#yield方法的含义,而不是yield关键字本身。

UPD_2:我发现了有关枚举器的有趣文章:“ Ruby 中的惰性枚举器”。

4

6 回答 6

23

在 Ruby 的上下文中, yield这个词并没有真正的特殊含义。它的含义与其他所有编程语言或编程和计算机科学中的含义相同。

当某种执行上下文将控制流交给不同的执行上下文时,通常使用它。例如,在 Unix 中,sched_yield一个线程可以使用一个函数将 CPU 让给另一个线程(或进程)。对于协程,该术语yield通常用于将控制从一个协程转移到另一个协程。在 C# 中,有一个yield关键字,迭代器方法使用该关键字将控制权交给迭代方法。

Enumerator::Yielder#yield事实上,最后一个用法与您所询问的 Ruby中方法的用法完全相同。调用此方法将暂停枚举器并放弃对枚举方法的控制。

例子:

fibs = Enumerator.new do |y|
  a, b = 0, 1
  y.yield a
  loop do
    y.yield b
    a, b = b, a + b
  end
end

puts fibs.next #  0
puts fibs.next #  1
puts fibs.next #  1
puts fibs.next #  2
puts fibs.next #  3
puts fibs.next #  5
puts fibs.next #  8
puts fibs.next # 13
puts fibs.next # 21

如您所见,有一个无限循环。显然,如果这个循环只是自己运行,它就没有多大用处。但由于每次调用该yield方法时,它都会放弃控制权,直到再次调用它,这将一一生成斐波那契数,本质上表示所有斐波那契数的无限长列表。

还有另一种方法,Fiber.yield,它具有类似的目的。(事实上​​,我已经在上面描述了它,因为Fiber它只是 Ruby 对协程的名称。)在 aFiber中,您调用Fiber.yield将控制权交还给最初将控制权交给您的执行上下文。

最后,有一个yield关键字,在方法体中使用它来放弃对传递给方法的块的控制。

请注意,至少在这种Enumerator情况下(即第一个示例),您可以另外解释yield产生,因为Enumerator每次调用时都会产生一个新值yield

于 2011-02-21T20:16:48.550 回答
3

在枚举器中让步的上下文中,其含义最接近“带来”。Enumerator 调用其 yielder 对象的 yield 方法,该方法“产生”任何传递给它的值。

give_me = Enumerator.new do |yielder|
  (1..5).each do |n|
    yielder.yield n
  end
end

5.times do
  p give_me.next
end

这导致:
1
2
3
4
5

在屈服于块的情况下,其含义最接近“投降”。带有 yield 语句的方法将执行交给您传递给该方法的任何块。

def wage_war
  p "What should I do?"
  yield
end

wage_war { p "Surrender!" }
于 2011-02-21T19:22:27.047 回答
3

您可能会发现阅读 Programming Ruby 1.9 对yield关键字的说明会很有趣:

编程语言爱好者会很高兴知道yield选择该关键字是为了与 Liskov 的 CLU 语言中的 yield 函数相呼应,该语言已有 30 多年的历史,但包含仍未被 CLU-less 广泛利用的功能.

更多阅读:

CLU 的历史(pdf)

芭芭拉·利斯科夫(维基百科)

于 2011-02-21T22:41:00.850 回答
2

@Prostosuper,我最喜欢的相关定义是这个

让步,让步,授予(放弃;放弃或放弃对他人的物理控制)

在@Jamie Forrest 的示例中,当调用工资战争时,“我该怎么办?” 首先打印,然后将流控制(让步、割让、授予、让步)交给调用工资战争的块,从而产生“投降!正在打印。该块完成后,流控制在工资战争中恢复。如果yield后面还有一条语句,就会在“Surrender!”之后在wage_war中恢复流控时执行。被打印出来了。

编辑:@Prostosuper 询问 yield 因为它与Enumerators相关,而不是块,我的示例讨论了它在块中的使用。关于 Enumerator::Yielder#yield 的 SO 问题(带答案)在这里。定义的意义仍然适用。

于 2011-02-21T19:39:26.243 回答
0

yield,在 ruby​​ 上下文中“带来”:) 块作为参数传递给您的方法。

def my_method
    p "I have to say something:"
    yield
end

my_method do
   p "hello world!"
end

印刷

I have to say something:
hello world

当 my_method 达到 yield 时执行代码 p "hello world"

于 2011-02-21T18:20:22.147 回答
0

在 c# 中,循环中的 yield 类似于 return 关键字,并且是迭代列表的循环的一部分。那为什么不使用 return 呢?因为使用yield,您可以在迭代该列表中的值时将控制权交还给循环。所以yield可能更像是一种控制机制。

于 2020-09-27T08:34:25.960 回答