41

我是 Ruby 新手,有没有办法yield从 Ruby 函数中获取值?如果是,如何?如果没有,我有什么选择来编写惰性代码?

4

5 回答 5

59

Ruby 的yield关键字与 Python 的同名关键字有很大的不同,所以不要被它弄糊涂了。Ruby 的yield关键字是用于调用与方法关联的块的语法糖。

最接近的等价物是 Ruby 的 Enumerator 类。例如,Python 的等价物:

def eternal_sequence():
  i = 0
  while True:
    yield i
    i += 1

这是:

def eternal_sequence
  Enumerator.new do |enum|
    i = 0
    while true
      enum.yield i # <- Notice that this is the yield method of the enumerator, not the yield keyword
      i +=1
    end
  end
end

您还可以使用 为现有的枚举方法创建枚举器enum_for。例如,('a'..'z').enum_for(:each_with_index)为您提供小写字母的枚举器及其在字母表中的位置。您可以使用 1.9 中的标准 Enumerable 方法免费获得它each_with_index,因此您只需编写('a'..'z').each_with_index即可获取枚举器。

于 2010-03-24T00:55:40.770 回答
24

我见过以这种方式使用的Fibers ,请看本文中的一个示例:

fib = Fiber.new do  
  x, y = 0, 1 
  loop do  
    Fiber.yield y 
    x,y = y,x+y 
  end 
end 
20.times { puts fib.resume }
于 2010-03-24T09:02:40.530 回答
15

如果您希望懒惰地生成值,@Chuck 的答案是正确的。

如果您希望对集合进行惰性迭代,Ruby 2.0 引入了新的.lazy枚举器。

range = 1..Float::INFINITY
puts range.map { |x| x+1 }.first(10) #  infinite loop
puts range.lazy.map { |x| x+1 }.first(10) #  [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
于 2015-05-16T16:18:16.397 回答
6

Ruby 支持开箱即用的生成器,使用Enumerable::Generator

require 'generator'

# Generator from an Enumerable object
g = Generator.new(['A', 'B', 'C', 'Z'])

while g.next?
  puts g.next
end

# Generator from a block
g = Generator.new { |g|
  for i in 'A'..'C'
    g.yield i
  end

  g.yield 'Z'
}

# The same result as above
while g.next?
  puts g.next
end

https://ruby-doc.org/stdlib-1.8.7/libdoc/generator/rdoc/Generator.html

于 2018-06-27T17:59:17.990 回答
0

Enumerator及其方法的next行为相似 https://docs.ruby-lang.org/en/3.1/Enumerator.html#method-i-next

range = 1..Float::INFINITY
enumerator = range.each

puts enumerator.class # => Enumerator

puts enumerator.next  # => 1
puts enumerator.next  # => 2
puts enumerator.next  # => 3
于 2022-02-10T20:21:58.777 回答