为啥 Rust 不能为传递给过滤器的闭包推断正确的类型?

Posted

技术标签:

【中文标题】为啥 Rust 不能为传递给过滤器的闭包推断正确的类型?【英文标题】:Why does Rust not infer the right type for a closure passed to filter?为什么 Rust 不能为传递给过滤器的闭包推断正确的类型? 【发布时间】:2021-12-30 18:35:33 【问题描述】:

如果我有以下代码:

let a = 1;
let f = |n| n == &a;
let _: Vec<_> = (1u64..10).filter(f).collect();

Rust 强烈抱怨 collect 存在于相关的 Filter 结构中,但是闭包不满足特征绑定 FnMut

但是,如果我内联闭包或注释其参数类型,则代码可以工作,例如:

let a = 1;
let _: Vec<_> = (1u64..10).filter(|n| n == &a).collect();

或:

let a = 1;
let f = |n: &u64| n == &a;
let _: Vec<_> = (1u64..10).filter(f).collect();

这是为什么?内联闭包而不注释类型的事实确实很奇怪。我认为这是因为n 将其类型推断为u64 而不是&amp;u64,因为范围有某种被消耗的倾向,但我不知道。

【问题讨论】:

【参考方案1】:

我不知道确切的规则,但是根据我在使用 Rust 时观察到的情况,在不需要特定类型的情况下创建闭包总是会导致从可用的信息中推断出类型仅闭包声明——而不是稍后如何使用闭包值。也就是说,Rust 的类型推断在这种情况下不再是“双向的”。例如:

let f = |x| x.clone();
f("hello world");
error[E0282]: type annotations needed
  --> src/main.rs:11:14
   |
11 |     let f = |x| x.clone();
   |              ^ consider giving this closure parameter a type
   |
   = note: type must be known at this point

此示例无法编译,因为编译器没有使用来自对f调用 的信息来决定x 应该是&amp;str

在你的情况下,我不确定到底是什么问题。

我认为这是一个生命周期问题(参数生命周期被推断为借用 a 的生命周期,而不是任意生命周期),但我认为 |n: &amp;u64| 无济于事。

另一个假设是,问题在于== 运算符是伪装的PartialEq::eq 调用,它并不能推断该调用的Self 类型是什么(因为除了u64 之外的其他类型可以实现PartialEq&lt;&amp;u64&gt;。但我预计会看到另一个“需要类型注释”错误,要求您缩小要使用的特征实现。

我没有准确的解释,但通常你应该期望当你将闭包的定义与其用法分开时,你可能需要添加更多的类型注释。

【讨论】:

以上是关于为啥 Rust 不能为传递给过滤器的闭包推断正确的类型?的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能快速推断闭包类型

rust - 将闭包传递给特征方法: expected type parameter,发现闭包

为啥 TS 中的泛型接口不能正确推断类型?

VB 2015 的 闭包(Closure)

为啥当值为假时我不能传递过滤数据(它是布尔值)

为啥指针不能传递正确的值(C)?