How can one pass an iterator to a method that consumes some of it?

Apologies if this is long winded, I want to make myself as clear as I can be.
Ok so here is what I would like this code to do:

  1. Create a peekable iterator out of some values
  2. loop and Consume the elements of the iterator and check what they are
  3. Depending on what each element is, I want to pass what is left of the iterator to a method
  4. That method should then consume some indeterminate number of elements from that iterator
  5. When the method concludes, the loop in main should continue consuming what is left of iterator after the methods consume elements by both consuming elements and sending the iterator back to the methods

What I thought I was doing was passing the iterator in exactly the state that it was in when I make the method call in main, but apparently this isnt happening, because while while let Some(value) = iterator.peek() works in main, it doesnt work in the methods, It gives me "no method named peek found for type parameter impl Iterator<Item = &’a str> in the current scope"

fn main() {
    let vector = vec!["skip", "value","value", "save","value", "skip", "value","value", "save", "value",];
    let mut iterator = vector.iter().copied().peekable();
    while let Some(value) = iterator.peek() {
        match *value {
            "skip" => {
                iterator.next(); // Discarding the value we peeked at
                skip_values(iterator.by_ref())
            },
            "save" => {
                iterator.next(); // Discarding the value we peeked at
                save_values(iterator.by_ref())
            },
            _ => (),
        }
    }
}
fn skip_values<'a>(mut iterator: impl Iterator<Item = &'a str>){
    while let Some(value) = iterator.peek() { // Ensuring iterator is not empty
        if value != "skip" && value != "save" {
            iterator.next(); // discard value 
        } else {
            break;
        }
    }
}
fn save_values<'a>(mut iterator: impl Iterator<Item = &'a str>){
    while let Some(value) = iterator.peek() { // Ensuring iterator is not empty
        if value != "skip" && value != "save" {
            iterator.next(); // discard value
        } else {
            break;
        }
    }
}

And just to get ahead of this: This is just a simpler way of reproducing the error I am running into in my code. I know full well that if I actually wanted to accomplish the above behavior there are easier ways.

I have tried redeclaring the iterator as iterator.peekable(), but then I run into the issue that it says I am borrowing its value in a previous iteration of the loop.

In the simplest terms, I want to be able to loop through the iterator I pass into the method in a nearly identical way as I do in main.

I know that I am not consuming the entire iterator in main because I can still call next() on it in the method without issue.

>Solution :

For the functions to be able to peek, you need to declare their parameters as being Peekable, not just an arbitrary iterator. This revision of your code compiles, with that and a few other tweaks to make the types line up:

use std::iter::Peekable;
fn main() {
    let vector = vec!["skip", "value","value", "save","value", "skip", "value","value", "save", "value",];
    let mut iterator = vector.iter().copied().peekable();
    while let Some(value) = iterator.peek() {
        match *value {
            "skip" => {
                iterator.next(); // Discarding the value we peeked at
                skip_values(iterator.by_ref());
            },
            "save" => {
                iterator.next(); // Discarding the value we peeked at
                save_values(iterator.by_ref());
            },
            _ => (),
        }
    }
}
fn skip_values<'a>(iterator: &mut Peekable<impl Iterator<Item = &'a str>>){
    while let Some(&value) = iterator.peek() { // Ensuring iterator is not empty
        if value != "skip" && value != "save" {
            iterator.next(); // discard value 
        } else {
            break;
        }
    }
}
fn save_values<'a>(iterator: &mut Peekable<impl Iterator<Item = &'a str>>){
    while let Some(&value) = iterator.peek() { // Ensuring iterator is not empty
        if value != "skip" && value != "save" {
            iterator.next(); // discard value
        } else {
            break;
        }
    }
}

Leave a Reply