Reputation: 1347
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?
Upvotes: 1
Views: 216
Reputation: 88546
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
.
Upvotes: 3
Reputation: 65692
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.)
Upvotes: 3