【问题标题】:Error message with unboxed closures未装箱闭包的错误消息
【发布时间】:2015-01-09 19:27:29
【问题描述】:

这个使用未装箱闭包的小 FizzBu​​zz 程序给出了一个相当神秘的错误消息。

fn fizzbuzz<F: Fn(i64) -> bool>(n: i64, f: F, fs: &str, b: F, bs: &str) {
    for i in range(1i64, n+1) {
        match (f(i), b(i)) {
            (true, true) => println!("{:3}: {}{}", i, fs, bs),
            (true, _)    => println!("{:3}: {}", i, fs),
            (_, true)    => println!("{:3}: {}", i, bs),
            _            => (),
        }
    }
}

fn main() {
    fizzbuzz(30,
             |&: i: i64| { i % 3 == 0 }, "fizz",
             |&: j: i64| { j % 5 == 0 }, "buzz");
}

错误信息:

<anon>:15:14: 15:40 error: mismatched types: expected `closure[<anon>:14:14: 14:40]`, found `closure[<anon>:15:14: 15:40]` (expected closure, found a different closure)
<anon>:15              |&: j: i64| { j % 5 == 0 }, "buzz");
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

有人能描述一下错误吗?谢谢。

【问题讨论】:

  • 请在问题正文中包含回答您的问题所需的所有详细信息(即代码)。问题不应该依赖于外部链接,因为从长远来看它们往往会中断,我们正在尝试建立一个长期资源。干杯。
  • 请在您的问题中直接包含相关(且仅相关)代码和错误消息,而不是要求人们点击可能不可信的链接。

标签: rust


【解决方案1】:

这段代码说明了问题的本质:

fn show_both<S: Show>(x: S, y: S) {
    println!("{} {}", x, y);
}

您只能使用两个参数相同类型调用它,也就是说,这是允许的:

let x: i32 = 10;
let y: i32 = 20;
show_both(x, y);

但这不是:

let x: i32 = 10;
let y: f64 = 20.0;
show_both(x, y);

这很自然:您指定两个参数必须是相同的类型,即使这种类型可以是任意的,只要它实现了Show

您的代码中的内容基本相同:

fn fizzbuzz<F: Fn(i64) -> bool>(n: i64, f: F, fs: &str, b: F, bs: &str)

您声明fb 必须具有相同的类型。然而,对于每个未装箱的闭包,编译器都会生成一个不同的类型——这也是很自然的,因为不同的闭包可以捕获不同的变量。

你需要指定不同的类型参数才能传递不同的闭包:

fn fizzbuzz<F1, F2>(n: i64, f: F1, fs: &str, b: F2, bs: &str)
    where F1: Fn(i64) -> bool,
          F2: Fn(i64) -> bool

【讨论】:

    【解决方案2】:

    每个未装箱的闭包定义都会创建一个完全不同的类型。这使得main 中定义的每个闭包都成为不同的类型。另一方面,您的fizzbuz 函数要求传递给它的每个闭包都是同一类型,F。如果你把fizzbuzz的签名改为:

    fn fizzbuzz<F: Fn(i64) -> bool, G: Fn(i64) -> bool>(n: i64, f: F, fs: &str, b: G, bs: &str)
    

    您的代码将进行类型检查。

    基本上,&lt;F: Fn(i64) -&gt; bool&gt; 语法不会为实现 trait 参数 (Fn(i64) -&gt; bool) 的类型创建通配符,而是声明一个必须满足 trait 参数并且在任何使用它的地方都是相同类型的单一类型。未装箱的闭包定义必须是不同的类型,因为它们可能包装不同的环境,也因为它们分派给不同的函数(即,每个函数都有不同的主体)。因此,fizzbuzz 需要两个不同的类型参数来适应这两种闭包类型。

    【讨论】:

      猜你喜欢
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 2017-09-02
      • 2020-03-06
      • 2020-08-16
      • 2011-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多