为什么Fuse迭代器适配器无法按预期工作?

有翼的潜艇

我正在尝试使用Fuse迭代器适配器,并且得到了意外的结果(Playground链接):

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

迭代器i1返回了我期望的结果。它返回None,然后Some(2),然后Nonei2与相同的迭代器fuse()保险丝应使其None在第一个之后返回None,并且由于它返回的第一个值是None它应该返回的唯一值。但是,其行为与相同i1我究竟做错了什么?

Shepmaster

TL; DR摘要:这是一个错误,已在Rust 1.19和更高版本中修复。

我很确定您没有做错任何事情。这似乎是一个错误(我的猜测)或一个非常令人困惑的交互。查看以下扩展示例:

#![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并且开始返回None,则scan它将继续返回None但是,这并不是唯一的方法None-闭包也可以返回None

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章