I'm trying to write a function which takes a slice of numbers and calculates the mean.
I tried using the ideas from Implementing mean function for generic types but get an error.
My code is:
extern crate num;
use num::{FromPrimitive, Zero};
use std::ops::{Add, Div};
fn main() {
let mut numbers = [10, -21, 15, 20, 18, 14, 18];
let err = "Slice is empty.";
println!("Mean is {:.3}", mean(&numbers).expect(err));
}
fn mean<T>(numbers: &[T]) -> Option<f64>
where
T: Copy + Zero + Add<T, Output = T> + Div<T, Output = T> + FromPrimitive,
{
match numbers.len() {
0 => None,
_ => {
let sum = numbers.iter().sum: ();
let length = FromPrimitive::from_usize(numbers.len()).unwrap();
Some(sum / length)
}
}
}
The error is:
error[E0658]: type ascription is experimental (see issue #23416)
--> src/main.rs:20:23
|
20 | let sum = numbers.iter().sum: ();
| ^^^^^^^^^^^^^^^^^^^^^^
Is there any way of writing a generic mean function without using experimental features?
The other answers will likely help you with your real problem of writing this function generically.
The actual error you've asked about though is just a syntax mistake. You wrote this:
But almost certainly intended to write:
The compiler has seen the
:
that you have accidentally included, and thinks that you are trying to use type ascription. Type ascription is syntax to use type annotations inline within an expression, instead of just in variable declarations.What you wrote is very similar to:
If you were to enable type ascription in a nightly rustc build, the error would change because now the compiler will tell you that
sum
is a function and definitely does not have type()
.How about this:
Same code in the Rust Playground
It seems to have the following advantages over the answers posted so far:
num
crate.FromPrimitive
andZero
.Or this version which has the following differences to the one above:
Thanks to my friend Sven for code contribution.
When the compiler can't figure out the type
S
offn sum<S>(self) -> S
, you either need to writelet foo: Bar = baz.sum();
orlet foo = baz.sum::<Bar>();
If you are sure that
T
will always be some type of number primitive, you ought to collect a owned type fromsum()
withlet sum: T = numbers.iter().cloned().sum();
and add thecore::iter::Sum
bound toT
. Otherwise, you may want to work with references.You can make your function a little more generic be returning
Option<T>
but if you really want to returnOption<f64>
, you should castT
tof64
using theToPrimitive
trait. Like this.Your type also needs to implement
Sum<T>
, so you need to add theSum
bound too. This is not enough, you also need to convert your generic type to af64
. The num crate also has theToPrimitive
trait to do this:Playground