【问题标题】:Why does Rust not infer this closure's return type?为什么 Rust 不推断这个闭包的返回类型?
【发布时间】:2021-01-14 21:13:27
【问题描述】:

Rust 编译器通常能够推断从闭包返回的表达式的类型:

fn main() {
    let a_closure = |num|{
        num+1.0
    };
    println!("{}", a_closure(1.0));
}

但是当我定义相同的闭包using a return statement时编译器无法推断类型:

fn main() {
    let a_closure = |num|{
        return num+1.0
    };
    println!("{}", a_closure(1.0));
}

/*
    error[E0308]: mismatched types
     --> src/main.rs:3:9
      |
    3 |         return num+1.0
      |         ^^^^^^^^^^^^^^ expected `()`, found `f64`
*/

我很惊讶 Rust 不能在这里推断类型:是否可以在闭包中使用 return 语句而不阻止编译器推断其返回类型?

【问题讨论】:

  • 有趣的是,添加类型注释num: f64 修复了使用return 时的编译。缺乏推理可以作为编译器的错误或功能请求提交。但是,令人困惑的错误消息可能被视为错误。消息“预期为(),发现f64”似乎不适合该示例,注释num: f64 看起来不应该影响它。
  • 该消息适用于该错误,它表示 rustc 推断返回类型为(),但我们返回的是f64。请注意fn foo() { 1.0f64 } 如何触发完全相同的错误消息(除了 它 建议添加返回类型)。
  • 调用 a_closure(1.0f64) 也可以解决问题。
  • 向闭包添加显式返回类型也可以修复错误:|num| -> f64 { return num+1.0 }
  • @Masklinn 如果编译器的推论受到要求() 作为返回类型的约束的支持,则错误消息将是适当的,但这里的情况并非如此。这就是为什么我认为该消息令人困惑,或者至少具有误导性:它似乎暗示了这种不存在的约束。此外,foo 和 return foo; 之间的区别(最后的分号没有区别)似乎是一个直接的错误。

标签: rust type-inference


【解决方案1】:

这是由于缺少分号。如果没有分号,则返回最后一个表达式,最后一个表达式是return num + 1.0。由于 return 语句使程序跳转到某个地方,否则它的值可以是任何值,例如:

fn main() {
    let a: String = return;
}

但是,如果编译器发现没有分配给它的直接类型,它将选择类型() 作为返回语句的值。

所以发生了什么:

  1. 编译器会看到闭包中的最后一个表达式,并默认为其分配类型()。
  2. 然后编译器会在闭包内看到一个显式返回,它返回类型 i32。

因此,由于有两次尝试从闭包返回,并且每次都返回不同的类型,所以这是类型不匹配。

【讨论】:

  • 这也是我的第一个猜测,但它是错误的:添加缺少的分号并不能修复错误。
  • 这无法解释为什么在代码中注释 any 的数字 return num + 1.0f64 或 a_closure(1.0f64) 或 |num: f64| { ... } 会导致错误消失,以及为什么这个错误似乎只表现在数值类型推断上(尝试使用特定于字符串的方法;没有任何问题)
猜你喜欢
  • 2019-05-28
  • 2021-07-17
  • 2021-08-28
  • 2019-01-09
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 2021-07-05
相关资源
最近更新 更多