Hi,
I am trying to write a generic vector and does a bunch of computation. In one step, I need to fold/reduce the values and this has proved much harder (and frustrating) than I thought. I am using rust 1.2.
Here is a simplified version,
extern crate num;
use std::ops::Add;
pub fn foo<T: Add + num::traits::Num >(a: Vec<T>) -> T {
let b = vec![1,2,3,5,7,8];
let z = b.iter().fold(0, |s,v| s+v);
let res = a.iter().fold(num::zero(), |sum, x| sum + x);
res
}
I get the following error,
src\utils.rs:15:51: 15:58 error: the trait `core::ops::Add<&T>` is not implement
ed for the type `T` [E0277]
src\utils.rs:15 let res = a.iter().fold(num::zero(), |sum, x| sum + x);
^~~~~~~
note: in expansion of closure expansion
As a related question, why is there not a simple Numeric
trait that provides basic numeric properties. I was unable to find one. In other words why do I need to work at the granularity of specifying Add, Sub etc ...
This is what works for me on playpen (using std::num
instead of num
since that's an external crate):
#![feature(zero_one)]
use std::ops::Add;
use std::num::Zero;
pub fn foo<T: Copy + Add<Output=T> + Zero>(a: Vec<T>) -> T {
let b = vec![1,2,3,5,7,8];
let z = b.iter().fold(0, |s,v| s+v);
let res = a.iter().fold(Zero::zero(), |sum, x| sum + *x);
res
}
fn main() {
foo(vec![1,2,3,4]);
}
BTW, you can replace let res = xxx; res
by xxx
1 Like
I get errors with that code
error: use of unstable library feature 'zero_one': unsure of placement, wants to use associated constants.
I would think that what I am trying to do would be fairly standard. Is there a simpler way to achieve this? Using a fold
and not with a loop
preferably.
The use of let res = xxx;
was only for debugging and to make it as similar to the preceding statement as possible. BTW, why is there a difference with the simple example? as in why *x
and not x
?
Thanks.
Did you try this (untested):
extern crate num;
use std::ops::Add;
pub fn foo<T: Add + num::traits::Num >(a: Vec<T>) -> T {
let b = vec![1,2,3,5,7,8];
let z = b.iter().fold(0, |s,v| s+v);
let res = a.iter().fold(num::zero(), |sum, &x| sum + x);
// ^
res
}
Note: &
is effectively the same as @birkenfeld suggested. Regarding why dereferencing: see these two analysis examples.
You should be fine using num
's trait instead. I just can't use that on playpen. But as you saw, the standard traits are still unstable, so feature(...)
only works on nightly Rust.
*x
is used to "make" a T
out of &T
, since the iterator yields &T
s but the Add
impl selected is for T + T -> T
.
It is possible to do this with the T + &T -> T
impl. The shortest generic spec I found for that is
pub fn foo<T: Copy + for<'r> Add<&'r T, Output=T> + Zero>(a: Vec<T>) -> T {
a.iter().fold(Zero::zero(), |sum, x| sum + x)
}
but it might be easier; I'll let the experts take over for that
Thanks for the replies. Here is the version that finally worked ...
extern crate num;
use std::ops::Add;
pub fn foo<T: Copy + Add<Output=T> + num::traits::Num>(a: Vec<T>) -> T {
a.iter().fold(num::zero(), |sum, x| sum + *x)
}
Great you got it to work. Don't be discouraged, Rust's generics system can be hard to start out with, since you have to specify quite a lot of bounds and it can get verbose. where
clauses can make it more readable.
However, I just had a look at the Num
trait and it already includes Add<Output=Self>
(and Sub
, Div
, ...) so a) you can leave out the Add
bound in your code and b) it answers the question from the first post ("why is there not a simple Numeric trait that provides basic numeric properties")