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

iai*_*ain 7 ruby

来自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
Run Code Online (Sandbox Code Playgroud)

但是当我创建枚举时Enumerator.new呢?

# 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
Run Code Online (Sandbox Code Playgroud)

我如何修改它以匹配API?

我尝试过的事情:

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
Run Code Online (Sandbox Code Playgroud)

有趣的是,当feed第二次调用时,它们都会产生相同的错误:

# Ignoring all the other errors that jump up…
p e2.next           #=> 1
e2.feed "a"
# nil
p e2.next           #=> 2
e2.feed "b"
Run Code Online (Sandbox Code Playgroud)

TypeError:已设置的Feed值

TypeError:已设置的feed值意味着它正在某处收集值,我只是不知道如何访问它.

#feed的C源代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

feedvalue我的目标也是如此.我已经使用Pry进入了该方法的操作,但找不到与feed或相关的方法或变量feedvalue.Rubinius明确地提供了这个(至少作为实例变量).

我很难过.

任何帮助或见解将不胜感激.

Cod*_*son 1

您的第一个示例是产量方法为的枚举器:map

e = [1,2,3].map
=> #<Enumerator: [1, 2, 3]:map>
Run Code Online (Sandbox Code Playgroud)

你的第二个例子是一个带有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> 
Run Code Online (Sandbox Code Playgroud)

您应该将to_enumenum_for与您选择的yield 方法一起使用:

[1,2,3].to_enum(:map)
=> #<Enumerator: [1, 2, 3]:map>
Run Code Online (Sandbox Code Playgroud)

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

Enumerator.new([1,2,3], :map)
Run Code Online (Sandbox Code Playgroud)

概括

总而言之,#map就是你的第一个迭代器调用的方法,当它被调用时,它的返回值将决定结果的值。当像其他示例一样使用时#each,以什么结束块 () 并不重要,#feed因为它不会影响 的返回值#each