Search code examples
rustclosures

How do I propagate an error outside of a closure?


I've got this little fragment in a function which returns Result:

list.sort_by(|a, b| a.re.partial_cmp(&b.re).unwrap()
                        .then(a.im.partial_cmp(&b.im).unwrap()));

but I don't like the unwrap. I'd rather replace the .unwrap() with ? but that gives me the error:

cannot use the `?` operator in a closure that returns `std::cmp::Ordering`

How can I propagate the error outside the closure?


Solution

  • You can't indicate an error via the return value of sort_by, and you can't abort the sort while it's under way. But you can smuggle the error out by accessing a mutable variable outside of the closure and returning a dummy value:

    let mut failed = false;
    list.sort_by(
        |a, b| match (a.re.partial_cmp(&b.re), a.im.partial_cmp(&b.im)) {
            (Some(reo), Some(imo)) => reo.then(imo),
            _ => {
                failed = true;
                Ordering::Equal
            }
        },
    );
    match failed {
        false => Ok(list),
        true => Err("I think not"),
    }
    

    Playground

    Though I suspect that you'd be better served by

    • first looking for NaNs in the list and not sorting at all if there are any (You can keep the unwraps then, as they'll really never occur), or
    • use something like ordered_float (or f64::total_cmp (stable since 1.62)) to make sure you can always sort (I haven't tried it yet, but it looks nice.)