简体   繁体   中英

How do I write a function in Rust that accepts any iterator whose Item fulfills a trait?

Here is a contrived example of what I'm trying to achieve:

trait Double {
    fn get(&self) -> i32;
}

impl Double for i32 {
    fn get(&self) -> i32 { self * 2 }
}

fn foo<'a, I: Iterator<Item = &'a Double>>(is: I) {
    for i in is {
        println!("{}", i.get());
    }
}

fn main() {
    let is = vec![1, 2, 3, 4];
    foo(is.into_iter());
}

The error here says "expected integral variable, found &Double ".

I'm having trouble googling for this as everywhere talks about iterators as traits. Is what I'm trying to do even possible?

Yes, it's possible. You need to use a where clause to specify a bound on the associated type I::Item .

fn foo<I>(is: I)
    where I: Iterator,
          I::Item: Double,
{
    for i in is {
        println!("{}", i.get());
    }
}

(I've also moved the I: Iterator bound to the where clause to keep all the bounds together.)

The bound Iterator<Item = &'a Double>> says that you want an iterator which yields items of exactly the type &Double which denotes the trait object of the trait Double . But you want an iterator that yields any type which implements the trait Double . This sounds very similar and thus confusing, but this is all about dynamic vs static dispatch. You should read the Rust book chapter about trait objects to understand what exactly is going on.

But a quick summary: there is a difference between writing

fn foo<T: MyTrait>(t: &T) {}

and

fn foo(t: &MyTrait) {}

You wrote code equivalent to the latter, but actually want the former.


So how do you express your intend in code? One possibility is to introduce another type parameter!

fn foo<'a, T, I>(is: I) 
    where T: Double,
          I: Iterator<Item = &'a T>,
{
    for i in is {
        println!("{}", i.get());
    }
}

But you can also just bound the associated type of the iterator (see Francis Gagné's answer ):

fn foo<I>(is: I) 
    where I: Iterator,
          I::Item: Double,
{ ... }

However, these two versions are slightly different as one accepts an iterator over references to types implementing Double while the other one iterates over types implementing Double directly. Just use what fits you the best or generalize those two things with traits like AsRef .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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