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.

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.