Justin Raymond
Justin Raymond

Reputation: 3558

How do I write the type of an iterator passed to a function?

I am trying to write a parser that passes an iterator over a vector to a function. The code is similar to this:

fn foo(itr : ???) {
    while let Some(c) = itr.next() {
        if *c != 0 {
            break;
        }
        println!("{}", *c);
    }
}

fn main() {
    let v = vec![0; 10];
    let itr = v.iter();
    while let Some(c) = itr.next() {
        foo(itr);
    }
}

I am not sure how to write the type of the iterator over the vector. I tried putting the wrong type u32 to see what type rustc expected: core::slice::Iter<'_, _>. When I try to use core::slice rustc complains Use of undeclared type or module 'core::slice'

Upvotes: 0

Views: 164

Answers (2)

Francis Gagn&#233;
Francis Gagn&#233;

Reputation: 65802

There are many types of iterators; most of the time, what you really want is a function that is able to consume any of them. To do this, the idiomatic solution is to use generics.

fn foo<'a, T: Iterator<Item=&'a i32>>(mut itr: T) {
    while let Some(c) = itr.next() {
        if *c != 0 {
            break;
        }
        println!("{}", *c);
    }
}

fn main() {
    let v = vec![0; 10];
    let mut itr = v.iter();
    while let Some(c) = itr.next() {
        foo(itr);
    }
}

The code above doesn't compile though, since it moves itr into foo, then tries to use it again on the while let. To solve this, we need to pass the iterator by reference instead.

fn foo<'a, T: Iterator<Item=&'a i32>>(itr: &mut T) {
    while let Some(c) = itr.next() {
        if *c != 0 {
            break;
        }
        println!("{}", *c);
    }
}

fn main() {
    let v = vec![0; 10];
    let mut itr = v.iter();
    while let Some(c) = itr.next() {
        foo(&mut itr);
    }
}

Instead of generics, we can also use a trait object:

fn foo<'a>(itr: &mut Iterator<Item=&'a i32>) {
    while let Some(c) = itr.next() {
        if *c != 0 {
            break;
        }
        println!("{}", *c);
    }
}

fn main() {
    let v = vec![0; 10];
    let mut itr = v.iter();
    while let Some(c) = itr.next() {
        foo(&mut itr);
    }
}

The chapter on trait objects from the Rust book explains the difference between these solutions.

Upvotes: 3

Justin Raymond
Justin Raymond

Reputation: 3558

The solution was to add

use std::slice::Iter;

and the type was

fun foo<'a>(itr : &mut Iter<'a, i32>) {}

Upvotes: 0

Related Questions