如何为外部迭代创建可“克隆”的枚举器?

Ste*_*fan 4 ruby clone enumerator

我想通过nextis- cloneable为外部迭代创建一个枚举器,以便克隆保留当前的枚举状态。

举个例子,假设我有一个方法,它返回一个枚举数,它产生平方数

def square_numbers
  return enum_for(__method__) unless block_given?

  n = d = 1
  loop do
     yield n
     d += 2
     n += d
   end
end

square_numbers.take(10)
#=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Run Code Online (Sandbox Code Playgroud)

我想枚举前 5 个平方数,并为每个值打印随后的 3 个平方数。一些无关紧要的事情each_cons

square_numbers.take(8).each_cons(4) do |a, *rest|
  printf("%2d: %2d %2d %2d\n", a, *rest)
end
Run Code Online (Sandbox Code Playgroud)

输出:

 1:  4  9 16
 4:  9 16 25
 9: 16 25 36
16: 25 36 49
25: 36 49 64
Run Code Online (Sandbox Code Playgroud)

但与上述不同,我想使用两个嵌套循环以及and来使用外部迭代nextclone

outer_enum = square_numbers
5.times do
  i = outer_enum.next
  printf('%2d:', i)

  inner_enum = outer_enum.clone
  3.times do
    j = inner_enum.next
    printf(' %2d', j)
  end
  print("\n")
end
Run Code Online (Sandbox Code Playgroud)

不幸的是,上述尝试clone提出了一个:

def square_numbers
  return enum_for(__method__) unless block_given?

  n = d = 1
  loop do
     yield n
     d += 2
     n += d
   end
end

square_numbers.take(10)
#=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Run Code Online (Sandbox Code Playgroud)

我知道 Ruby 没有提供这种开箱即用的功能。但是我怎么能自己实现呢?我怎样才能创建一个Enumerator支持clone

认为,它是实施的问题initialize_copy和用于复制这两个变量值nd,但我不知道如何或在哪里做。

kgi*_*pin 6

Ruby 纤程无法复制,并且 Enumerator 的 C 实现存储了一个指向纤程的指针,该纤程似乎不会以任何方式暴露给 Ruby 代码。

https://github.com/ruby/ruby/blob/752041ca11c7e08dd14b8efe063df06114a9660f/enumerator.c#L505

if (ptr0->fib) {
    /* Fibers cannot be copied */
    rb_raise(rb_eTypeError, "can't copy execution context");
}
Run Code Online (Sandbox Code Playgroud)

查看 C 源代码,很明显 Enumerators 和 Fibers 以非常深刻的方式联系在一起。所以我怀疑有没有办法改变initialize_copyto permit的行为clone