Closures don't need type annotations, but sometimes they need

fn f<R>(callback: impl Fn(Option<usize>) -> R) -> R { callback(Some(123)) }

fn test_f() {
    f(|_| {}); // ok
    let callback = |u| {}; // ok
    f(callback);
    f(|u| u.and(Some(345))); // ok
    
    let callback = |u: Option<usize>| u.and(Some(345)); // ok
    f(callback);
    //let callback = |u| u.and(Some(345)); // error[E0282]: type annotations needed
    //f(callback);
    //let callback = |u: _| u.and(Some(345)); // error[E0282]: type annotations needed
    //f(callback);
}

For callback: impl Fn(usize) -> R, we don't need annotations at all.
Is there any rule for this behavior?

There's no rule as such so far as I know.

In practice, as soon as you introduce a method or field (use .), the compiler seems to want to know what it's dealing with immediately, as opposed to inferring it from a wider context.

The other infamous case for closures is when you need to deal with anything higher ranked, like taking a reference with any lifetime vs. a specific inferred lifetime, or especially taking any lifetime and returning something with the same lifetime. Sometimes you can do something as simple as

let callback = |u: &_| ...

for the takes-a-reference-with-any-lifetime case.

1 Like