 # Passing generic vector of numbers

I'm learning Rust and want to understand how I can pass a vector of numbers (any kind) to a function. This code does not compile, but I can't figure out how to fix it:

``````use std::ops::{Add, Div};

fn average<T: Add + Div>(numbers: &Vec<T>) -> T {
let sum: T = numbers.iter().fold(0, |acc, n| acc + n);
sum / numbers.len()
}

fn main() {
let numbers: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];
println!("average2 = {}", average(&numbers));
}
``````

I understand I can use `numbers.iter().sum()`, but I want to learn about `fold`.
The compiler complains about:

• zero as the first argument to fold
• `acc + n`
• the return expression in the average function

The `T` type might not be an integer, so you can't use 0.

1 Like

You could look into the `num-traits` crate.

``````use num_traits::cast::FromPrimitive;
use num_traits::identities::{zero, Zero};
use std::ops::Div;

fn average<T: Zero + Div<Output = T> + Clone + FromPrimitive>(
numbers: &[T],
) -> T {
let sum: T = numbers.iter().cloned().fold(zero(), |acc, n| acc + n);
sum / T::from_usize(numbers.len()).unwrap()
}

fn main() {
let numbers: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];
println!("average2 = {}", average(&numbers));
}
``````

You can use `Default` trait to get zero value (most of the time). See also num-traits for more traits you can use.

When you say it's a type `T: Add + Div` Rust assumes it can be any type that implements them, including types created in the future that don't exist yet. It could be a matrix. It could be a string. It could be an image. There is nothing that limits `Add` or `Div` to numbers.

Thanks steffahn! Is this the simplest way to write a function that computes the average of a list of numbers in Rust or is there a better approach?

Thanks kornel! I tried changing my average function to this:

``````fn average<T: num_traits::Num>(numbers: &Vec<T>) -> T {
let sum: T = numbers.iter().fold(Default::default(), |acc, n| acc + n);
sum / numbers.len()
}
``````

It's unhappy with my use of `Default::default()` and `numbers.len()`.
I'm not sure how to fix it from here.

You have to declare absolutely every operation you could possibly use on the type, so use `T: Num + Default` to have `Default` available.

`len()` gives you `usize`, but there's no guarantee that `T` can be divided by `usize`. Rust doesn't have implicit numeric conversions, so only `usize` can be divided by `usize`.

Theoretically you can add `T: From<usize>` and use `T::from(numbers.len())`, but due to portability concerns very few data types can be converted from `usize`.

Instead of returning `T` you could return `f64` and use num-traits' trait for casting types to `f64` and divide it as a concrete type.

But Rust's generics are a very poor fit for numeric code. On every step Rust will make you ask "but what if the `T` is an array or a string or a file handle? How would I divide a friggin file handle by `usize`!?"

• Consider using macros. They're not type-safe and closer to templates in C++, so you don't have to declare as much (but you will still need to cast `usize` to whatever type you divide)
• Consider using concrete types. Do you really need to support every possible type?
• Consider using type aliases, e.g. `type MyNum = f64`. That makes it slightly easier to switch to another type if you change your mind later.
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.