[英]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:有人可以解释一下:
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.