如果它期望函数类型作为类型参数,如何键入None ?



假设我有一个接受回调的函数

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

假设我现在想让这个回调成为可选的。在我看来,最明显的方法是使用Option:

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

然而,当这样做时,我在使用站点遇到了一个问题。例如,以下代码不能编译:

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

我得到以下错误:

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`.

然而,似乎不可能为此提供类型,因为impl …语法在这里不能作为类型参数,并且无论如何都需要来自闭包的具体类型。

有可能像这样为缺失的闭包注释类型吗?

您必须为其提供实现FnOnce(u8) -> u8的类型,因为这是foo所需的,我能想到的最简单的类型是函数指针:

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

有几种方法。您需要选择一个实现FnOnce(T) -> T的类型。对于示例,我将使用fn(T) -> T,但它没有太大区别:

  • 使用涡轮鱼:
foo(None::<fn(u8) -> u8>, 123);
  • 使用带有类型归属的let绑定
let option_fn: Option<fn(u8) -> u8> = None;
foo(option_fn, 123);
  • 将泛型命名,并在foo上使用turbofish:
fn foo<T, F: FnOnce(T) -> T>(f: F, t: T) -> T {
...
}
foo::<u8, fn(u8) -> u8>(None, 123);

作为现有答案的替代方案,提供恒等函数(返回其参数的函数)将是这里更合适的函数风格,并且具有使整个问题解决的优点。它也可能执行得更好,因为没有分支可以被错误地预测。

fn identity<T>(v: T) -> T { v }
fn foo<T>(callback: impl FnOnce(T) -> T, value: T) -> T {
callback(value)
}
fn bar() -> u8 {
let value: u8 = b'.';
let value = foo(identity, value);
value
}

换句话说,使用Option实际上可能是浪费当"无功能"将导致与恒等函数相同的可观察行为。

(当然,|v| videntity短,所以您使用哪个是个人喜好的问题。)

这并不能解决如何在可选函数的上下文中指定None的一般问题,当标识函数不应该导致与没有函数相同的行为时。其他答案则是关于如何处理这种情况。当两种情况具有相同的行为时,此答案旨在提供更好的解决方案。

最新更新