为什么Fuse迭代器适配器不能按预期工作?

时间:2017-05-12 22:07:52

标签: iterator rust

我尝试使用Fuse迭代器适配器并获得意外结果(Playground link):

fn main() {
    let mut i1 = (1..3).scan(1, |_, x| {
        if x < 2 { None } else { Some(x) }
    });
    println!("{:?}", i1.next());
    println!("{:?}", i1.next());
    println!("{:?}", i1.next());
    println!("");

    let mut i2 = (1..3).scan(1, |_, x| {
        if x < 2 { None } else { Some(x) }
    }).fuse();
    println!("{:?}", i2.next());
    println!("{:?}", i2.next()); // This should print None
    println!("{:?}", i2.next());
    println!("");
}

打印哪些:

None
Some(2)
None

None
Some(2)
None

Iterator i1正在回归我的期望。它返回None,然后是Some(2),然后是Nonei2fuse()一致的迭代器相同。保险丝应该在第一个None之后返回None,并且因为它返回的第一个值是None,它应该是它返回的唯一值。但是,它的行为与i1相同。我做错了什么?

1 个答案:

答案 0 :(得分:5)

我很确定你没有做错任何事。这似乎是一个错误(我的猜测)或非常混乱的交互。看看这个扩展的例子:

#![feature(fused)]

fn dump<I: Iterator<Item = i32>>(label: &str, mut iter: I) {
    println!("= Running: {}", label);
    for _ in 0..10 {
        println!("{:?}", iter.next());
    }
    println!("");
}

fn boxed_internal_fuse() -> Box<Iterator<Item = i32>> {
    Box::new((1..3)
        .scan(1, |_, x| if x < 2 { None } else { Some(x) })
        .fuse())
}

fn boxed_no_fuse() -> Box<Iterator<Item = i32>> {
    Box::new((1..3)
        .scan(1, |_, x| if x < 2 { None } else { Some(x) }))
}

use std::iter::FusedIterator;
fn boxed_no_fuse_but_fused() -> Box<FusedIterator<Item = i32>> {
    Box::new((1..3)
        .scan(1, |_, x| if x < 2 { None } else { Some(x) }))
}

fn main() {
    let i1 = (1..3)
        .scan(1, |_, x| if x < 2 { None } else { Some(x) });
    dump("Scan", i1);

    let i2 = (1..3)
        .scan(1, |_, x| if x < 2 { None } else { Some(x) })
        .fuse();
    dump("Fuse<Scan>", i2);

    dump("Box<Fuse<Scan>>", boxed_internal_fuse());
    dump("Fuse<Box<Iterator>>", boxed_no_fuse().fuse()); // All `None`s
    dump("Fuse<Box<FusedIterator>>", boxed_no_fuse_but_fused().fuse());
}

诀窍是FusedIterator是一种旨在提高效率的不稳定特征。它让Iterator::fuse知道这是一个无操作。

然而,在这种情况下,条件是必要的但不充分:

impl<B, I, St, F> FusedIterator for Scan<I, St, F>
    where I: FusedIterator, F: FnMut(&mut St, I::Item) -> Option<B> {}

如果底层迭代器FusedIterator并且开始返回Nonescan将继续返回None。但是,这不是获取None的唯一方法 - 闭包也可以返回None