Rust Turbofish: Closure Return Type

Posted February 5, 2022 ‐ 2 min read

There is a compiler type error in Rust that can happens when you try to pass a closure that returns a Result type.

error[E0282]: type annotations needed
  --> src/main.rs:27:9
   |
27 |         Ok(())
   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`

The clue to how to solve this is already in the error message - we need to add type annotations. But why does this happen?

Suppose you have a wrapper that accepts a closure to be wrapped in execution:

fn your_wrapper<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    println!("Before");
    let v = f();
    println!("After");
    v
}

When using this wrapper, we can have two error types and use the wonderful thiserror crate to implement a From trait between them.

use thiserror::Error;

#[derive(Error, Debug)]
enum Error {}

#[derive(Error, Debug)]
enum MainError {
    #[error("Sub error: {0}")]
    Sub(#[from] Error),
}

fn main() -> Result<(), MainError> {
    let r = your_wrapper(|| {
        println!("Inside wrapper");
        Ok(())
    })?;

    println!("Following call");
    Ok(r)
}

The limitation stems from how the main function is written. The Result is deconstructed and reconstructed back. However, there is no way for the compiler to come up a concrete type for the Ok(()) value, and this is because no error value or type signature was involved in the definition of the closure.

Turbofish syntax to the rescue

This is where the turbofish syntax comes handy. The fix is to define the closure as such:

let r = your_wrapper(|| {
    println!("Inside wrapper");
    Ok::<_, Error>(())
})?;

We can use this to specify the type of the error without repeating the type of the value or the identifier Result. This pattern is often repeated, so I have casually defined an Ok::<_, Error>(()) snippet in my editor for quick typing.


Share this post
Follow author