为什么这个闭包参数需要显式类型?

5
考虑以下工作的代码
fn f() {
    let xs = vec![(0, 0)];
    let f = |j| xs[j];
    let y = f(0usize);
}

以下变量无法编译:
fn f() {
    let xs = vec![(0, 0)];
    let f = |j| xs[j].0;
    let y = f(0usize);
}

它失败了,如下所示:
error[E0282]: type annotations needed
 --> src/lib.rs:3:17
  |
3 |     let f = |j| xs[j].0;
  |                 ^^^^^ cannot infer type
  |
  = note: type must be known at this point

要修复它,必须注释j:
fn f() {
    let xs = vec![(0, 0)];
    let f = |j: usize| xs[j].0;
    let y = f(0usize);
}

Rust book中提到:

与fn函数不同,闭包不要求您注释参数或返回值的类型。

为什么必须显式声明j的类型?

1个回答

0

如@Stargateur所建议的重复中所解释的那样,Rust需要知道索引的类型,以便确定结果的类型。在您的第一个示例中,这不是问题,因为您没有使用xs[j]或闭包的结果,因此编译器可以将它们留作“某些尚未定义的类型”,并优化掉而无需知道类型。

然而,在您的第二个示例中,您尝试访问xs[j].0,对于这个,编译器需要知道xs[j]的类型,以便知道如何处理.0


编译器需要知道 xs[j] 的类型,才能知道如何处理 .0。那么这个代码也不应该编译通过吧? - Ömer Erden
在你的例子中,编译器看到 y 从未被使用,因此我认为它不会尝试完全检查 rhs 表达式。在 OP 的情况下,xs[j].0 被用作闭包的返回值。我认为编译器不能轻易地跨函数(或闭包)边界进行优化,这就是为什么它没有看到该返回值从未被使用并且可以被忽略的原因。 - Jmb
不行,仍然可以使用 printing y。从我的角度来看,编译器无法从 index(_) 的输出类型中找到 index(_) 输入的类型。这是正常的,因为根据 SliceIndex 的实现,输出 可以是任何东西,但它似乎也没有从 f(0usize) 这一行推断出输入类型,也许问题应该是为什么不从 f(0usize) 推断? - Ömer Erden
如果涉及到行顺序,它会解释为什么 f(0usize).0 能够工作,因为输入类型已知。但是我不知道类型检查算法是如何工作的。 - Ömer Erden
好观点。我也不知道它的详细工作原理,但这不是我第一次看到在类型信息向前流动而不是向后流动时它的效果更好。 - Jmb

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