为什么 Rust 不能推断传递给 filter 的闭包的正确类型?

4

如果我有以下代码:

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 而不是 &u64 ,但我不确定。
1个回答

2

我不知道确切的规则,但从我使用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 应该是 &str
在你的情况下,我不确定问题具体是什么。
- 我会认为这是一个生命周期问题(参数的生命周期被推断为借用的 a 的生命周期而不是任意生命周期),但我也觉得 |n: &u64| 不会有所帮助。 - 另一种假设是问题在于 == 运算符是一个伪装成 PartialEq::eq 调用的运算符,它不能推断出该调用的 Self 类型(因为某些类型除了 u64 之外也可以实现 PartialEq<&u64>)。但我会期望看到另一个 “需要类型注释” 的错误,要求你缩小使用哪个 trait 实现。 - 我没有确切的解释,但一般来说,当你将闭包的定义与其使用分开时,你可能需要添加更多的类型注释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接