简体   繁体   English

如何使用 Rust 的 Peekable?

[英]How to use Rust's Peekable?

I'm interested in peeking ahead in a character stream.我有兴趣在字符流中提前查看。 To my understanding, Peekable would be the way to go.据我了解, Peekable将是要走的路。 I can't quite figure out how to use it.我不能完全弄清楚如何使用它。

First attempt:第一次尝试:

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());
}

This fails to compile with这无法编译

> 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

Okay, fair enough.好吧,够公平。 I don't fully understand traits yet so I try to pass an iterator in and then create a peekable version:我还没有完全理解特征,所以我尝试传入一个迭代器,然后创建一个可查看的版本:

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());
}

This fails with这失败了

> 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

Could someone explain:有人可以解释一下:

  • why Peekable couldn't appear in the function type for lack of being a trait,为什么 Peekable 由于缺乏特性而不能出现在函数类型中,
  • what the compiler means when it says 'move out of dereference of' and编译器说“移出取消引用”和
  • how I might resolve either or both?我如何解决其中一个或两个?

A third version第三个版本

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());
}

This fails with:这失败了:

> 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

I fail to understand what rust is saying to me here, how Iterator.next would have a different return type from Peekable.peek.我无法理解 rust 在这里对我说的是什么,Iterator.next 如何与 Peekable.peek 具有不同的返回类型。

Peekable is not a trait and thus cannot be used as a bound, which would suggest that it could mean one of many types. Peekable不是特征,因此不能用作界限,这表明它可能意味着许多类型之一。 It is a single, specific, concrete type, struct Peekable<A, T> .它是一个单一的、特定的、具体的类型struct Peekable<A, T> As you have observed, it's constructed by calling the peekable() method on an iterator, which changes it to something that is peekable.正如您所观察到的,它是通过调用迭代器上的peekable()方法构建的,该方法将其更改为可查看的内容。

Here's how you'd use it if you just wanted to take an iterator:如果您只想使用迭代器,可以使用以下方法:

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

Note also that the peekable() method takes self by value;还要注意peekable()方法按值获取 self ; you can't take a mutable reference to an iterator there.你不能对那里的迭代器进行可变引用。

The alternative which is what you were aiming for but which I would be generally less inclined towards, would be to require the argument to be peekable, putting the burden onto the caller, as you had:您的目标是替代方案,但我通常不太倾向于这样做,那就是要求参数是可窥视的,将负担推给调用者,就像您所做的那样:

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

Peekable is actually a struct, not a trait. Peekable实际上是一个结构体,而不是特征。 If you wanted to take a Peekable , you could define your function like this:如果你想要一个Peekable ,你可以像这样定义你的函数:

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

Your second implementation is failing to compile because peek takes self by value (ie it consumes the iterator, returning a new one), so you can't call it through a &mut reference.您的第二个实现无法编译,因为peek按值获取self (即它消耗迭代器,返回一个新的迭代器),因此您不能通过&mut引用调用它。 Most code simply takes the iterator by value instead of by reference:大多数代码只是通过值而不是引用来获取迭代器:

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

If you don't want to move the iterator into a function like trawl , you can use the by_ref() method to create a new iterator that holds onto an &mut reference:如果您不想将迭代器移动到像trawl这样的函数中,您可以使用by_ref()方法创建一个新的迭代器来保存&mut引用:

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

As far as style goes, I would say that the second form is the better way to go, as the first leaks what's basically an implementation detail.就风格而言,我会说第二种形式是更好的方法,因为第一种形式泄露了基本上是实现细节的内容。

Rust has changed a bit since the previous answers.自从之前的答案以来,Rust 已经发生了一些变化。 The way to do it now is:现在的做法是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM