Why is a type annotation needed for this addition/sum?


#1

The following code doesn’t work unless I annotate s (or sum).

let s : f64 = us.samples.iter().map(|&sample| {
	if !sample.is_diagnosed() {
		f64::from(sample.rank)
	} else if !us.can_fulfill( &sample ) {
		10f64 //we want to discard
	} else {
		0f64
	}
}).sum();
s + (MAX_SAMPLES - us.samples.len()) as f64

I can’t figure out why it needs an annotation as all the output of the map appears to be an f64, and both sides of the addition are f64.


#2

All calls to sum need type annotation.

(maybe not correct explanation, can see someone else giving different.)
https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum
To avoid type annotation the compiler has to find a single data type to substitute for generic S. Since data types can be made from generic (or there can be generic implementation of Sum) there is potentially infinite types to search.

It is easy enough to make an alternate.

struct Foo;
impl ::std::iter::Sum<f64> for Foo {
    fn sum<I>(iter: I) -> Self where I: Iterator<Item = f64> {
        Foo
    }
}

Alternatively; Imagine if it worked without. Your using a crate and that crate gets updated with a implementation. Your code would suddenly break from the second choice.


#3

Yeah, I think that’s correct. It’s sort of the same thing as Into::into - the output is generic and destination type needs to be known (or inferred).


#4

Correcting myself, this isn’t strictly true; it can be inferred with use of subsequent statement.
Not with + since Add is generic.

fn i(i:f64) -> f64 {i}
let sum = i(sum);