【问题标题】:Are there something like Python generators in Ruby?Ruby 中有类似 Python 生成器的东西吗?
【发布时间】:2011-01-31 01:28:47
【问题描述】:

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

【问题讨论】:

    标签: ruby lazy-evaluation


    【解决方案1】:

    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

    【讨论】:

      【解决方案2】:

      如果您希望懒惰地生成值,@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]
      

      【讨论】:

        【解决方案3】:

        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) 为您提供小写字母的枚举器以及它们在字母表中的位置。您可以使用标准的 Enumerable 方法(如 1.9 中的 each_with_index)免费获得此功能,因此您只需编写 ('a'..'z').each_with_index 即可获取枚举器。

        【讨论】:

        • 0.step 从 1.9 开始就是一个永恒的枚举器
        【解决方案4】:

        我见过Fibers是这样使用的,看看this article的例子:

        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 }
        

        【讨论】:

        • 实际上,在 Ruby 1.9 中的Enumerator 是使用Fiber 实现的。实际上,这是添加它们的主要原因之一,因为在 Ruby 1.8 Enumerators 中使用延续,但那是 a) 相当笨拙,并且 b) 那时将要从 Ruby 语言中删除延续。跨度>
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-30
        • 2020-04-10
        • 1970-01-01
        相关资源
        最近更新 更多