代码之家  ›  专栏  ›  技术社区  ›  Jason

在Ruby中使用to_enum创建可枚举对象的优点是什么?

  •  12
  • Jason  · 技术社区  · 15 年前

    为什么要在Ruby中通过使用to_enum方法而不是直接使用对象来创建对对象的代理引用?我想不出这有什么实际用途,试图理解这个概念&有人可能会使用它,但我看到的所有例子似乎都很琐碎。

    例如,为什么使用:

    "hello".enum_for(:each_char).map {|c| c.succ }
    

    而不是

    "hello".each_char.map {|c| c.succ }
    

    我知道这是一个非常简单的例子,有人有真实世界的例子吗?

    5 回复  |  直到 11 年前
        1
  •  16
  •   Marc-André Lafortune    12 年前

    大多数接受块的内置方法都会在没有提供块的情况下返回枚举数(如 String#each_char to_enum ; 两者的效果相同。

    不过,有几个方法不返回枚举数。在这种情况下,您可能需要使用 .

    # How many elements are equal to their position in the array?
    [4, 1, 2, 0].to_enum(:count).each_with_index{|elem, index| elem == index} #=> 2
    

    再比如,, Array#product , #uniq #uniq! 我过去不接受封锁。在1.9.2中,这一点有所改变,但为了保持兼容性,没有块的表单不能返回 Enumerator . 仍然可以“手动”使用 要获取枚举数,请执行以下操作:

    require 'backports/1.9.2/array/product' # or use Ruby 1.9.2+
    # to avoid generating a huge intermediary array:
    e = many_moves.to_enum(:product, many_responses)
    e.any? do |move, response|
      # some criteria
    end 
    

    主要用途 当您实现自己的迭代方法时。您通常会将以下内容作为第一行:

    def my_each
      return to_enum :my_each unless block_given?
      # ...
    end
    
        2
  •  3
  •   Marcin    15 年前

    我认为这与内部和外部迭代器有关。返回如下所示的枚举数时:

    p = "hello".enum_for(:each_char)
    

    因此,使用外部迭代器可以执行以下操作,例如:

    p = "hello".enum_for(:each_char)
    loop do
        puts p.next
    end
    
        3
  •  3
  •   jakeonrails    13 年前

    假设我们要获取一个键数组和一个值数组,并将它们缝合在一个散列中:

    def hashify(k, v)
      keys = k.to_enum(:each)
      values = v.to_enum(:each)
      hash = []
      loop do
        hash[keys.next] = values.next
        # No need to check for bounds,
        # as #next will raise a StopIteration which breaks from the loop
      end
      hash
    end
    

    没有#到#枚举:

    def hashify(k, v)
      hash = []
      keys.each_with_index do |key, index|
        break if index == values.length
        hash[key] = values[index]
      end
      hash
    end
    

    读第一种方法要容易得多,你不觉得吗?不是很简单,但是想象一下如果我们以某种方式操纵3个数组中的项目?5.10?

        4
  •  1
  •   mikej heading_to_tahiti    15 年前

    这不是你问题的答案,但希望它是相关的。

    each_char 不经过一个街区。无块调用时 每个字符 返回一个 Enumerator

    irb(main):016:0> e1 = "hello".enum_for(:each_char)
    => #<Enumerator:0xe15ab8>
    irb(main):017:0> e2 = "hello".each_char
    => #<Enumerator:0xe0bd38>
    irb(main):018:0> e1.map { |c| c.succ }
    => ["i", "f", "m", "m", "p"]
    irb(main):019:0> e2.map { |c| c.succ }
    => ["i", "f", "m", "m", "p"]
    
        5
  •  1
  •   Petr Skocik    10 年前

    例如,下面将为您提供整个斐波那契序列的枚举数,从0到无穷大。

    def fib_sequence
      return to_enum(:fib_sequence) unless block_given?
      yield 0
      yield 1
      x,y, = 0, 1
      loop { x,y = y,x+y; yield(y) }
    end
    

    to_enum yields 不必麻烦 Fiber s

    然后,您可以根据需要对其进行切片,这将非常节省内存,因为内存中不会存储任何数组:

    module Slice
        def slice(range)
            return to_enum(:slice, range) unless block_given?
            start, finish = range.first, range.max + 1
            copy = self.dup
            start.times { copy.next }
            (finish-start).times { yield copy.next }
        end
    end
    class Enumerator
        include Slice
    end
    
    fib_sequence.slice(0..10).to_a
    #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    fib_sequence.slice(10..20).to_a                                                                                                                           
    #=> [55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]