ruby - 如何为外部迭代创建一个 "clone"的枚举器?

标签 ruby clone enumerator

我想通过 next 创建一个用于外部迭代的枚举器即 clone -able,以便克隆保留当前枚举状态。
举个例子,假设我有一个方法返回一个枚举器,它产生 square numbers :

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]
我想枚举前 5 个平方数,并为每个值打印随后的 3 个平方数。与 each_cons 无关的事情:
square_numbers.take(8).each_cons(4) do |a, *rest|
  printf("%2d: %2d %2d %2d\n", a, *rest)
end
输出:
 1:  4  9 16
 4:  9 16 25
 9: 16 25 36
16: 25 36 49
25: 36 49 64
但与上述不同,我想使用两个嵌套循环以及 next 来使用外部迭代。和 clone :
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
不幸的是,上面试图clone提出一个:
`initialize_copy': can't copy execution context (TypeError)
我知道 Ruby 没有提供这种开箱即用的功能。但是我怎么能自己实现呢?如何创建 Enumerator支持clone ?
我认为这是实现 initialize_copy 的问题并复制 n 的两个变量值和 d ,但我不知道如何或在哪里做。

最佳答案

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");
}
查看 C 源代码,很明显 Enumerators 和 Fibers 以非常深刻的方式联系在一起。所以我怀疑是否有任何方法可以改变 initialize_copy 的行为允许 clone .

关于ruby - 如何为外部迭代创建一个 "clone"的枚举器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62637661/

相关文章:

c# - 接口(interface)实现和返回类型

ruby-on-rails - 我得到 "found character that cannot start any token while scanning for the next token"

ruby - 在 TeamCity 上构建和测试命令行 Gem

javascript - 对克隆表单进行验证

javascript - 克隆和选择框 onchange 更改输入文本的值

javascript - 不在 dom 中的克隆元素的 getComputedStyle

ruby - 在 ruby​​ 中将子类方法作为函数参数传递

ruby-on-rails - 将附加参数传递给 Controller

ruby - Prime.new 已过时 - 如何重写此代码?

c# - 如何获取所有任务