我想通过 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/