I'm a novice Rust programmer. What I would like to do is a function such as this that operates over any iterable with numbers. Here is the function I started with as a base:
fn multiplier(values: &Vec<f64>) -> f64 {
values.iter().fold(1.0, |acc, val| acc * val)
}
I've tried quite a few things, and although I feel like I am getting closer I am now feeling somewhat defeated.
Here is a sorry tale of a few attempts and my thought patterns as I was working through the issues:
At first, I thought that it might be a matter of saying that I need an iterator that has items that can be multiplied. I'm pretty much shooting in the dark at this stage, so I plug this in and see what happens:
use std::ops::{Mul}; // it took reading a few error messages to do this
fn multiplier<I:Iterator, T:Mul>(vals: I<T>) -> T{
vals.fold(1.0, |acc, val| acc * val)
}
That code seems to make the compiler very unhappy.
I try searching the web for "generic iterators". I came across SO question that references a reddit thread that seems authoritative and tried modifying the syntax to suit. (As an aside, my naive eyes see the second version in that example as much clearer, despite it apparently being the wrong way to do things.)
fn multiplier<I:Iterator>(vals: I) -> f64 where I::Item: Mul {
vals.fold(1.0, |acc, val| acc * val) as f64
}
<anon>:19:31: 19:40 error: the trait `core::ops::Mul<<I as core::iter::Iterator>::Item>` is not implemented for the type `_` [E0277]
I don't really understand this explanation. Where did the underscore type come from? Still, I press on slightly. Maybe it would help if I declare T
to be Mul
, the implication being that T would some how magically connected to I
.
fn multiplier<I:Iterator, T:Mul>(vals: I) -> f64 where I::Item: Mul {
vals.fold(1.0, |acc, val| acc * val)
}
<anon>:19:32: 19:41 error: the trait `core::ops::Mul<<I as core::iter::Iterator>::Item>` is not implemented for the type `f64` [E0277]
Sigh. The f64
type doesn't know how to multiply. I think that is what this is saying?
Maybe if I remove the specific type on the return value?
fn multiplier<I:Iterator, T>(vals: I) -> T where I::Item: Mul {
vals.iter().fold(1.0, |acc, val| acc * val)
}
<anon>:61:11: 61:15 error: no method named `iter` found for type `I` in the current scope
<anon>:61 vals.iter().fold(1.0, |acc, val| acc * val)
Nope.
Try into_iter()
?
fn multiplier<I:Iterator, T>(vals: I) -> T where I::Item: Mul {
vals.into_iter().fold(1.0, |acc, val| acc * val)
}
<anon>:65:27: 65:30 error: mismatched types:
expected `T`,
found `_`
(expected type parameter,
found floating-point variable) [E0308]
<anon>:65 vals.into_iter().fold(1.0, |acc, val| acc * val)
^~~
This kinda sorta looks like it's a bit happier. But it wants a T
. As I think to myself "How do I say that I want 1*T where T is numeric?", I do as I am asked..
fn multiplier<I:Iterator, T:Mul>(vals: I) -> T where I::Item: Mul {
vals.into_iter().fold(T, |acc, val| acc * val)
}
<anon>:73:27: 73:28 error: unresolved name `T` [E0425]
<anon>:73 vals.into_iter().fold(T, |acc, val| acc * val)
...
<anon>:73:47: 73:50 error: mismatched types:
expected `T`,
found `<I as core::iter::Iterator>::Item`
(expected type parameter,
found associated type) [E0308]
<anon>:73 vals.into_iter().fold(T, |acc, val| acc * val)
^~~
Even though I was fairly sure that it wouldn't work, it's still disappointing to see red pop up on screen.
Any suggestions?