如何使我的枚举器接口接受Feed?

时间:2018-02-25 17:36:08

标签: ruby

来自docs for Ruby v2.5

lastValue

但是当我通过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

如何修改此内容以匹配API?

我尝试过的事情:

# a naive rework of the above enum
e2 = Enumerator.new do |y|
  [1,2,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

有趣的是,当第二次调用e2 = Enumerator.new do |y| [1,2,3].each do |x| @fed = yield y << x end raise StopIteration, @fed end e2 = Enumerator.new do |y| [1,2,3].each do |x| y << yield(x) end raise StopIteration, y end e2 = Enumerator.new do |y| enum = [1,2,3].each{|x| yield x }.to_enum y << enum.next raise StopIteration, y end 时,它们都会产生相同的错误:

feed
  

TypeError:已设置Feed值

TypeError:已设置的Feed值表示它正在收集值某处,我只是不知道如何访问它。

#feed的C源:

# Ignoring all the other errors that jump up…
p e2.next           #=> 1
e2.feed "a"
# nil
p e2.next           #=> 2
e2.feed "b"

所以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; } 是我的目标。我已经使用Pry进入了该方法的操作,但无法找到与feedvaluefeed相关的方法或变量。 Rubinius makes this available explicitly(至少作为实例变量)。

我很难过。

非常感谢任何帮助或见解。

2 个答案:

答案 0 :(得分:3)

你的第一个例子以它的方式工作的原因是因为你使用#map“将数组的元素传递给”yield“并将”yield“的结果收集为数组。”在Enumerator#feed http://ruby-doc.org/core-2.5.0/Enumerator.html#method-i-feed

中有一个有趣的注释

无论如何,如果您还在其上调用map,您的自定义枚举器的行为方式与第一个示例中的数组相同:

e2 = Enumerator.new { |y|
  [1,2,3].each do |x|
    y << x
  end
}.map

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      #=> ["a", "b", "c"]
end

答案 1 :(得分:1)

您的第一个示例是枚举数,其yield方法为:map

e = [1,2,3].map
=> #<Enumerator: [1, 2, 3]:map>

您的第二个示例是一个枚举数,其yield方法为:each

e2 = Enumerator.new do |y|
  [1,2,3].each do |x|
    y << x
  end
  # raise StopIteration, FED # <= how to get `FED`?
end
=> #<Enumerator: #<Enumerator::Generator:0x007fa69b056b50>:each> 

您应该使用to_enumenum_for和您选择的收益率方法:

[1,2,3].to_enum(:map)
=> #<Enumerator: [1, 2, 3]:map>

现在不推荐使用以下方式使用::new,因此我 NOT 建议使用它,而不是to_enumenum_for,它们提供相同的功能:

Enumerator.new([1,2,3], :map)

摘要

总结一下,#map是第一个迭代器调用的方法,当它是called时,它的return values将决定结果的值。与其他示例一样使用#each时,阻止阻止(#feed)的内容并不重要,因为它不会影响#each的返回值。