从
docs for Ruby v2.5
e = [1,2,3].map p e.next #=> 1 e.Feed "a" p e.next #=> 2 e.Feed "b" p e.next #=> 3 e.Feed "c" begin e.next rescue StopIteration p $!.result #=> ["a","b","c"] end
但是当我通过Enumerator.new创建枚举时呢?
# a naive rework of the above enum e2 = Enumerator.new do |y| [1,3].each do |x| y << x end # raise StopIteration,FED # <= how to get `FED`? end p e2.next #=> 1 e2.Feed "a" p e2.next #=> 2 e2.Feed "b" p e2.next #=> 3 e2.Feed "c" begin e2.next rescue StopIteration p $!.result #=> nil end
我如何修改它以匹配API?
我尝试过的事情:
e2 = Enumerator.new do |y| [1,3].each do |x| @fed = yield y << x end raise StopIteration,@fed end e2 = Enumerator.new do |y| [1,3].each do |x| y << yield(x) end raise StopIteration,y end e2 = Enumerator.new do |y| enum = [1,3].each{|x| yield x }.to_enum y << enum.next raise StopIteration,y end
# Ignoring all the other errors that jump up… p e2.next #=> 1 e2.Feed "a" # nil p e2.next #=> 2 e2.Feed "b"
TypeError: Feed value already set
TypeError:已设置的Feed值意味着它正在某处收集值,我只是不知道如何访问它.
static VALUE enumerator_Feed(VALUE obj,VALUE v) { struct enumerator *e = enumerator_ptr(obj); if (e->Feedvalue != Qundef) { rb_raise(rb_eTypeError,"Feed value already set"); } e->Feedvalue = v; return Qnil; }
所以Feedvalue是我的目标.我已经使用Pry进入了该方法的操作,但找不到与Feed或Feedvalue相关的方法或变量. Rubinius makes this available explicitly(至少作为实例变量).
我很难过.
任何帮助或见解将不胜感激.
解决方法
你的第一个例子是枚举数,其yield方法为:map:
e = [1,3].map => #<Enumerator: [1,3]:map>
你的第二个例子是一个枚举器,其yield方法为:each.
e2 = Enumerator.new do |y| [1,FED # <= how to get `FED`? end => #<Enumerator: #<Enumerator::Generator:0x007fa69b056b50>:each>
您应该使用to_enum或enum_for以及您选择的yield方法:
[1,3].to_enum(:map) => #<Enumerator: [1,3]:map>
以下方式使用:: new现在已弃用,因此我不建议使用它来支持提供相同功能的to_enum或enum_for:
Enumerator.new([1,3],:map)
总结一下,#map是第一个迭代器调用的方法,当它是called时,它的return values将决定结果的值.当像其他例子一样使用#each时,你的块(#Feed)结束并不重要,因为它不会影响#each的返回值.