Result type mismatch

In the link below I have a function that returns Result<HashMap<char,usize>,char>. The body of that function calls a helper function that returns Result<usize,char>. The errors are the same type signature, so returning on Err from the helper function causes no problem. In refactoring towards a more “functional” approach as an exercise I introduced a problem with the compiler. The first link shows the error, the second the workaround I employed. Is this the best way I can get around this problem?

http://play.rust-lang.org/?gist=187cc4527fa220389ac39d9edf074f71&version=stable&mode=debug&edition=2015

http://play.rust-lang.org/?gist=bbb52df91ec8da2516aade8505a3f8af&version=stable&mode=debug&edition=2015

The compiler error happens because you try to convert Result<T1, E> into Result<T2, E> where T1 and T2 are different types. While you know at runtime that the value is always a Err at that location, the compiler doesn’t know that. A quick fix is to extract E from the Result using err().unwrap() and then wrap it into a Result of a correct type (which will be inferred):

if err.len() > 0 { return Err(err[0].1.err().unwrap()); }

However, the function can be simplified if you use the fact that an iterator that yields Result can be collected into a Result with a collection (it will be Ok if iterator yielded Ok every time and Err if the iterator returned an Err):

pub fn nucleotide_counts(dna: &str) -> Result<HashMap<char, usize>, char> {
    NUCLEOTIDES.iter().map(|&n| count(n,dna).map(|r| (n, r))).collect()
}

The .map(|r| (n, r)) uses a method of Result that modifies the Ok payload. We want to add n to the Result while keeping it the top level type so that collect() works (i.e. it will work on Result<(char, usize), _> but won’t work on (char, Result<usize, _>).

2 Likes

Wow, what a great explanation! Makes it quite clear, thanks.