This is a common question, and the surprising answer is, no.
Like Iterator::collect, it is generic over its output type.
use std::iter::Sum;
#[derive(Clone,Copy,Debug)]
struct Imposter(u8);
impl Sum<u8> for Imposter {
fn sum<I>(iter: I) -> Imposter where I: Iterator<Item=u8> {
let mut acc = Imposter(0u8);
for x in iter {
acc = Imposter(acc.0 + x);
}
acc
}
}
fn main() {
let a = vec![1u8; 10];
println!("{:?}", a.iter().cloned().sum::<u8>()); // 10
println!("{:?}", a.iter().cloned().sum::<Imposter>()); // Imposter(10)
}
Suppose there was also an impl for Imposter<u8>: Into<char> which, say, always returned 'A'. Then certainly, bytes.sum().into::<char>() would be ambiguous!
In all fairness, it does seem to me the existing implementations of Sum for standard library types could, in theory, uniquely determine the output type–but only if Sum were somehow closed to new implementations.
As to why there’s this funny Sum trait that is generic over its output, well here’s a short history lesson: Iterator::sum used to be a little different:
fn sum<S = Self::Item>(self) -> S
where S: Add<Self::Item, Output=S> + Zero
{
self.fold(Zero::zero(), |s, e| s + e)
}
It still required just as many type annotations as it does today; but with this definition, the motivation for making the function generic over the return type might be plainer to see.
However, Zero and One were never stabilized and left to the num crate instead. Eventually the traits left in std were ripped out and replaced with the backwards-compatible Sum trait.