Search code examples
genericsrusttypesoption-type

How to type None if it expects a function type as type argument?


Suppose I have a function that takes a callback

fn foo<T>(callback: impl FnOnce(T) -> T, value: T) -> T {
    callback(value)
}

Suppose I now want to make this callback optional. The, in my view, most obvious way of doing that is to use Option:

fn foo<T>(callback: Option<impl FnOnce(T) -> T>, value: T) -> T {
    if let Some(callback) = callback {
        callback(value)
    } else {
        value
    }
}

However, when doing this, I run into a problem at the use site. For instance, the following code does not compile:

fn bar() -> u8 {
    let value: u8 = b'.';
    let value = foo(None, value);
    value
}

I get the following error:

error[E0282]: type annotations needed
  --> XX:XX:XX
   |
XX |     let value = foo(None, value);
   |                     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
   |
help: consider specifying the generic argument
   |
XX |     let value = foo(None::<T>, value);
   |                         +++++

For more information about this error, try `rustc --explain E0282`.

However, it seems impossible to provide a type for this, as impl … syntax does not work as a type argument here, and you’d need a concrete type from a closure anyways.

Is it possible to annotate the type for a missing closure like this?


Solution

  • You have to provide it a type that implements FnOnce(u8) -> u8 since that is what foo requires, the simplest one I can think of is a function pointer:

    fn bar() -> u8 {
        let value: u8 = b'.';
        let value = foo(None::<fn(_) -> _>, value);
        value
    }