Generic parameters not working in Iterator


#1

generic parameters works in this simple case:

fn cube<T>(x: T) -> T
where T: Copy + Mul<Output = T>
{
    x * x * x
}

But when I use it in a more complex way it stopped working:

fn dot_productT<T>(a: Vec<T>, b: Vec<T>) -> T
where T: Sum + Copy + Mul<Output = T>
{
    return a.iter().zip(b.iter()).map(|(x, y)| x*y).sum();
}

Error message:

error[E0369]: binary operation `*` cannot be applied to type `&T`
  --> src\main.rs:16:48
   |
16 |     return a.iter().zip(b.iter()).map(|(x, y)| x*y).sum();
   |                                                ^
   |
note: an implementation of `std::ops::Mul` might be missing for `&T`
  --> src\main.rs:16:48
   |
16 |     return a.iter().zip(b.iter()).map(|(x, y)| x*y).sum();
   |                                                ^

error: aborting due to previous error

How can I fix this?


#2

You can deref x and y in the lambda or use “|(&x, &y)| x*y” in the lambda definition.


#3

It works, thanks!


#4

I dig a little further to make the code work for all iterator-able input:

pub fn dot<T: Sum + Copy + Mul<Output = T>, V: Iterator<Item=T>>(a: V, b: V) -> T
{
    return a.zip(b).map(|(x, y)| x*y).sum();
}

assert_eq!(4, util::dot(vec![2, 1].iter(), vec![2].iter()));

But ended up with the following error message:

error[E0277]: the trait bound `&{integer}: std::iter::Sum` is not satisfied
  --> src\lib.rs:22:23
   |
22 |         assert_eq!(4, util::dot(vec![2, 1].iter(), vec![2, 1].iter()));
   |                       ^^^^^^^^^ the trait `std::iter::Sum` is not implemented for `&{integer}`
   |
   = help: the following implementations were found:
   = help:   <f64 as std::iter::Sum>
   = help:   <f64 as std::iter::Sum<&'a f64>>
   = help:   <f32 as std::iter::Sum>
   = help:   <f32 as std::iter::Sum<&'a f32>>
   = help: and 40 others
   = note: required by `util::dot`

error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<&{integer}>` is not satisfied
  --> src\lib.rs:22:9
   |
22 |         assert_eq!(4, util::dot(vec![2, 1].iter(), vec![2, 1].iter()));
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialEq<&{integer}>` is not implemented for `{integer}`
   |
   = help: the following implementations were found:
   = help:   <&'a A as std::cmp::PartialEq<&'b B>>
   = help:   <&'a mut A as std::cmp::PartialEq<&'b mut B>>
   = help:   <&'a A as std::cmp::PartialEq<&'b mut B>>
   = help:   <&'a mut A as std::cmp::PartialEq<&'b B>>
   = help: and 606 others
   = note: this error originates in a macro outside of the current crate

error: aborting due to 2 previous errors

I can not even find a document for integer type. What am I missing?


#5

Yeah, the issue is that Vec::iter() gives you an iterator that returns references, &i32 in your case. The traits it’s complaining about are not implemented for &i32, only i32.

You have a few options here. First, you can bound V to be an IntoIterator, and then use "a.into_iter().zip(b.into_iter())… If you do that, you can pass just the vec itself as an arg, not vec.iter().

Second, you can specify that dot() operates on Iterator<Item=&'a T>. The signature will the look like:
fn dot<'a, T: 'a + …, V: Iterator<Item=&'a T> … The lambda inside the method will need to look like the one before, destructuring the references it’s given.

The first option consumes the object being converted to an iterator - so in your example the vecs wouldn’t be usable after had they been assigned to a variable binding.

The second option doesn’t consume since it’s working off references.

I’m on my phone so pardon the brevity/lack of formatting.