Summing a vector of u32 to get u64?

fn main() {
    let v: Vec<u32> = vec![100, 200, 300, 400];
    let sum = v.into_iter().sum::<u64>();
    println!("{:?}", sum)
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: a value of type `u64` cannot be made by summing an iterator over elements of type `u32`
    --> src/main.rs:3:35
     |
3    |     let sum = v.into_iter().sum::<u64>();
     |                             ---   ^^^ value of type `u64` cannot be made by summing a `std::iter::Iterator<Item=u32>`
     |                             |
     |                             required by a bound introduced by this call
     |
     = help: the trait `Sum<u32>` is not implemented for `u64`
     = help: the following other types implement trait `Sum<A>`:
               `u64` implements `Sum<&u64>`
               `u64` implements `Sum`
note: the method call chain might not have had the expected associated types
    --> src/main.rs:3:17
     |
2    |     let v: Vec<u32> = vec![100, 200, 300, 400];
     |                       ------------------------ this expression has type `Vec<u32>`
3    |     let sum = v.into_iter().sum::<u64>();
     |                 ^^^^^^^^^^^ `Iterator::Item` is `u32` here
note: required by a bound in `std::iter::Iterator::sum`
    --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:3518:12
     |
3515 |     fn sum<S>(self) -> S
     |        --- required by a bound in this associated function
...
3518 |         S: Sum<Self::Item>,
     |            ^^^^^^^^^^^^^^^ required by this bound in `Iterator::sum`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 1 previous error

This is an MRE of the issue at hand. I have a vector of u32 integers because each value is guranteed to be u32 but the vector's length can be anything. It's entirely possible for the sum of the vector to be more than u32. How do I handle this?

By explicitly converting the u32s into u64s.

fn main() {
    let v: Vec<u32> = vec![100, 200, 300, 400];
    let sum = v.into_iter().map(u64::from).sum::<u64>();
    println!("{:?}", sum)
}
7 Likes

Thank you.

Please mark their reply as the solution so this issue is known to be resolved and the solution can be found by other readers.

Done, thank you for reminding me. I keep forgetting that's a thing :sweat_smile:.

1 Like

Overengineered with an extension trait:

use std::iter::Sum;

pub trait SumAs<T> {
    fn sum_as(self) -> T;
}

impl<T, U> SumAs<T> for Vec<U>
where
    T: Sum,
    U: Into<T>,
{
    fn sum_as(self) -> T {
        self.into_iter().map(Into::into).sum()
    }
}

fn main() {
    let v: Vec<u32> = vec![100, 200, 300, 400];
    let sum: u64 = v.sum_as();
    println!("{:?}", sum)
}
2 Likes

Overengineered another step, move the generic onto the function so that the turbofish syntax can be used, as with sum:

trait SumAs: Iterator {
    fn sum_as<U>(self) -> U
    where
        <Self as Iterator>::Item: Into<U>,
        U: Sum,
    {
        self.map(Into::into).sum()
    }
}

impl<I: Iterator> SumAs for I {}

It's usually best practice to introduce generics as late as possible.

5 Likes