How to use Rust Peekable?

I am interested in looking ahead into the flow of characters. As far as I understand, Peekable is the way to go. I can’t figure out how to use it.

First try:

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 does not 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 

Good, right. I don't fully understand the features yet, so I'm trying to pass an iterator 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 does not work 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 

Can anyone explain:

  • why Peekable could not appear in the function type due to the lack of a sign,
  • what does the compiler mean when it says “go from dereferencing” and
  • How can I solve one or both?

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:

 > 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 don't understand what rust says here, as Iterator.next will have a different return type from Peekable.peek.

+6
source share
2 answers

Peekable not a sign and therefore cannot be used as a border, which suggests that it can mean one of many types. This is a specific concrete type, struct Peekable<A, T> . As you noticed, it was built by calling the peekable() method on an iterator that changes it to something that can be read.

This is how you use it if you just want 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 the value self by value; you cannot take a mutable link to an iterator.

An alternative to which you aspired, but to which I, as a rule, would be less inclined, would be to require that the argument be peeping, placing a burden on the caller, as is yours:

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

Peekable is actually a structure, not a feature. If you want to take Peekable , you can define your function as follows:

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

The second implementation does not compile, because peek takes the value self by value (i.e., consumes an iterator, returning a new one), so you cannot invoke it using the &mut link. Most of the code just takes an iterator by value, not 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 to a function like trawl , you can use the by_ref() method to create a new iterator that contains the &mut link:

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

Regarding the style, I would say that the second form is the best way to go, since the first leak is basically an implementation detail.

+4
source

Source: https://habr.com/ru/post/976653/


All Articles