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?
CodePudding user response:
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
}
CodePudding user response:
There are a few ways. You'll need to pick a type that implements FnOnce(T) -> T
. For the examples, I'll use fn(T) -> T
, but it doesn't make much difference:
- use a turbofish:
foo(None::<fn(u8) -> u8>, 123);
- use a let binding with a type ascription
let option_fn: Option<fn(u8) -> u8> = None;
foo(option_fn, 123);
- make the generics named, and use the turbofish on
foo
:
fn foo<T, F: FnOnce(T) -> T>(f: F, t: T) -> T {
...
}
foo::<u8, fn(u8) -> u8>(None, 123);