为什么在包含闭包的选项中“一种类型比另一种更通用”?

Pet*_*ete 14 rust

我写了一些编译好的代码,然后我变成TOption<T>,现在我收到了这个错误:

error[E0308]: mismatched type...one type is more general than the other
Run Code Online (Sandbox Code Playgroud)

在构建最小案例时,我注意到如果我更改data: &strdata: String代码再次编译正常。

游乐场链接

pub trait Subscriber {
    fn recv(&mut self, data: &str);
}

pub struct Task<T>(pub Option<T>)
where
    T: Fn(&str);

impl<T> Subscriber for Task<T>
where
    T: Fn(&str),
{
    fn recv(&mut self, data: &str) {
        self.0.take().unwrap()(data)
    }
}

fn main() {
    Task(Some(|_| ()));
}
Run Code Online (Sandbox Code Playgroud)

有人可以帮助我了解这里发生了什么吗?

E_n*_*ate 12

您似乎在编译器中遇到了一个怪癖。马桶盖 ( |_|()) 泛化为一个函数,该函数在其输入类型 ( <T> Fn(T)) 上是通用的,但在 的生命周期内不满足预期的约束T。由于forfor<'a> Fn(&'a str)的实现中的界限,我们在这里需要的是一个在输入的生命周期内通用的函数。SubscriberTask<T>

(由于当前的生命周期省略规则,Subscriber可以在不明确指出 的情况下编写排名较高的特征绑定for<'a>。为了清楚起见,在上一段中进行了扩展。)

如果您尝试将该Task值实际用作 a ,则编译器会更清楚地说明这一点Subscriber

let mut task = Task(Some(|_| ()));
task.recv("Message");
Run Code Online (Sandbox Code Playgroud)

错误信息:

error[E0599]: no method named `recv` found for struct `Task<[closure@src/main.rs:19:30: 19:36]>` in the current scope
  --> src/main.rs:20:10
   |
5  | / pub struct Task<T>(pub Option<T>)
6  | | where
7  | |     T: Fn(&str);
   | |                -
   | |                |
   | |________________method `recv` not found for this
   |                  doesn't satisfy `_: Subscriber`
...
19 |       let mut task = Task(Some(|_| ()));
   |                                ------
   |                                |
   |                                doesn't satisfy `<_ as std::ops::FnOnce<(&str,)>>::Output = ()`
   |                                doesn't satisfy `_: std::ops::Fn<(&str,)>`
20 |       task.recv("Message");
   |            ^^^^ method not found in `Task<[closure@src/main.rs:19:30: 19:36]>`
   |
   = note: the method `recv` exists but the following trait bounds were not satisfied:
           `<[closure@src/main.rs:19:30: 19:36] as std::ops::FnOnce<(&str,)>>::Output = ()`
           which is required by `Task<[closure@src/main.rs:19:30: 19:36]>: Subscriber`
           `[closure@src/main.rs:19:30: 19:36]: std::ops::Fn<(&str,)>`
           which is required by `Task<[closure@src/main.rs:19:30: 19:36]>: Subscriber`
Run Code Online (Sandbox Code Playgroud)

通过明确标志着封闭的单输入参数作为参考,关闭然后将不再概括了参数类型T,但是在参考输入的排名更高的寿命'a&'a _

let mut task = Task(Some(|_: &_| ()));
task.recv("Message");
Run Code Online (Sandbox Code Playgroud)

游乐场

虽然并非不可能,但调整编译器以成功推断原始闭包的正确类型可能需要对当前的单态化规则进行重大更改。

也可以看看: