如何使用Rust的Peekable?

时间:2014-10-13 05:30:07

标签: rust

我有兴趣在角色流中偷看。根据我的理解,Peekable将是最佳选择。我无法完全弄清楚如何使用它。

首次尝试:

fn trawl<I, E>(pk: &mut I) where I: std::iter::Peekable<Result<char, E>> {
    loop {
        let cur = pk.next();
        let nxt = pk.peek();
        match (cur, nxt) {
            (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
            _ => (),
        }
    }
}

fn main() {
    trawl(&mut std::io::stdio::stdin().chars());
}

无法使用

进行编译
> rustc /tmp/main.rs
/tmp/main.rs:1:37: 1:73 error: `std::iter::Peekable` is not a trait
/tmp/main.rs:1 fn trawl<I, E>(pk: &mut I) where I: std::iter::Peekable<Result<char, E>> {
                                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

好的,够公平的。我还没有完全理解特征,所以我尝试传递一个迭代器,然后创建一个可窥探的版本:

fn trawl<I, E>(it: &mut I) where I: Iterator<Result<char, E>> {
    let mut pk = it.peekable();
    loop {
        let cur = pk.next();
        let nxt = pk.peek();
        match (cur, nxt) {
            (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
            _ => (),
        }
    }
}

fn main() {
    trawl(&mut std::io::stdio::stdin().chars().peekable());
}

失败
> rustc /tmp/main.rs
/tmp/main.rs:2:18: 2:20 error: cannot move out of dereference of `&mut`-pointer
/tmp/main.rs:2     let mut pk = it.peekable();
                                ^~
/tmp/main.rs:7:65: 7:70 error: cannot move out of dereference of `&`-pointer
/tmp/main.rs:7             (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
                                                                               ^~~~~
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
/tmp/main.rs:7:39: 7:77 note: expansion site
error: aborting due to 2 previous errors

有人可以解释一下:

  • 为什么Peekable因为缺乏特质而无法出现在函数类型中,
  • 当编译器说“退出”&#39;和
  • 我怎么解决其中一个或两个?

第三个版本

fn trawl<I, E>(mut it: I) where I: Iterator<Result<char, E>> {
    let mut pk = it.peekable();
    loop {
        let cur = pk.next();
        let nxt = pk.peek();
        match (cur, nxt) {
            (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
            // (Some(i), ) => println!("{}", i.ok()),
            _ => (),
        }
    }
}

fn main() {
    trawl(std::io::stdio::stdin().chars().peekable());
}

这失败了:

> rustc /tmp/main.rs
/tmp/main.rs:7:65: 7:70 error: cannot move out of dereference of `&`-pointer
/tmp/main.rs:7             (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
                                                                               ^~~~~
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
/tmp/main.rs:7:39: 7:77 note: expansion site
error: aborting due to previous error

我无法理解生锈在这里对我说什么,Iterator.next将如何从Peekable.peek获得不同的返回类型。

3 个答案:

答案 0 :(得分:6)

Peekable不是特征,因此不能用作绑定,这表明它可能意味着许多类型中的一种。它是一种特定的具体类型struct Peekable<A, T>。正如您所观察到的,它是通过在迭代器上调用peekable()方法构造的,该方法将其更改为可以窥视的内容。

如果您只是想使用迭代器,那么您可以使用它:

fn trawl<I, E>(iter: I) where I: Iterator<Result<char, E>> {
    let pk = pk.peekable();
    …
}

另请注意peekable()方法取值为self;你不能在那里对迭代器进行可变引用。

你所瞄准的另一种选择,但我通常不太倾向于这种选择,就是要求论证是可以窥视的,把负担放在打电话上,就像你一样:

fn trawl<I, E>(pk: Peekable<E, I>) where I: Iterator<Result<char, E>> {
    …
}

答案 1 :(得分:5)

Peekable实际上是一个结构,而不是一个特征。如果你想要Peekable,你可以像这样定义你的函数:

fn trawl<E, I>(it: Peekable<I>) where I: Iterator<Result<char, E>> {
    ...
}

您的第二个实现无法编译,因为peek按值self获取(即消耗迭代器,返回一个新的迭代器),因此您可以&#39;通过&mut引用来调用它。大多数代码只是通过值而不是引用来获取迭代器:

fn trawl<E, I>(it: I) where I: Iterator<Result<char, E>> {
    let it = it.peekable();
    ...
}

如果您不想将迭代器移动到trawl之类的函数中,可以使用by_ref()方法创建一个保留&mut引用的新迭代器:

let mut my_iterator = /* whatever */;
trawl(my_iterator.by_ref());
// my_iterator is still usable here

就风格而言,我会说第二种形式是更好的方式,因为第一种方式泄漏的基本上是实施细节。

答案 2 :(得分:1)

自上次回答以来,铁锈已经改变了一点。现在要做的是:

fn trawl<I, E>(pk: Peekable<I>) 
where I: Iterator<Item = Result<char, E>> {
    …
}