rust - 为什么 "one type is more general than the other"在包含闭包的选项中?

标签 rust

我写了一些编译好的代码,然后我转了 T进入 Option<T>现在我收到了这个错误:

error[E0308]: mismatched type...one type is more general than the other
在构建最小案例时,我注意到如果我更改 data: &str进入 data: String代码再次编译正常。
Playground link
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(|_| ()));
}
有人可以帮助我了解这里发生了什么吗?

最佳答案

你似乎在编译器中遇到了一个怪癖。马桶盖 ( |_|() ) 泛化为一个函数,该函数在其输入类型 ( <T> Fn(T) ) 上是通用的,
但这种方式在 T 的生命周期内无法满足预期的约束.我们在这里需要的是一个函数,由于边界for<'a> Fn(&'a str),它在输入的生命周期内是通用的。在执行 SubscriberTask<T> .
(由于当前的生命周期省略规则, Subscriber 中排名较高的特征边界可以在不明确指示的情况下写入 for<'a> 。为清楚起见,在上一段中进行了扩展。)
如果您尝试实际使用 Task,编译器会更清楚地说明这一点。值作为 Subscriber :

let mut task = Task(Some(|_| ()));
task.recv("Message");
错误信息:
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`
通过明确地将闭包的单个输入参数标记为引用,闭包将不再泛化参数类型 T ,但在引用输入的更高排名生命周期内'a&'a _ .
let mut task = Task(Some(|_: &_| ()));
task.recv("Message");
Playground .
虽然并非不可能,但调整编译器以成功推断原始闭包的正确类型可能需要对当前的单态化规则进行重大更改。
也可以看看:
  • Why isn't `std::mem::drop` exactly the same as the closure |_|() in higher-ranked trait bounds?
  • 关于rust - 为什么 "one type is more general than the other"在包含闭包的选项中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63916821/

    相关文章:

    rust - 在 Rust 中创建一个连接 HashMap 键的字符串

    rust - 为什么我不能 `.iter()` 字符串切片?

    closures - 闭包作为函数参数 "cannot infer an appropriate lifetime due to conflicting requirements"

    macros - 如何创建宏来创建结构数组?

    rust - Rust 中的多重借用

    function - 如何在 Rust 中将函数作为参数传递

    rust - 如何在不将代码拆分成单独的函数的情况下为SPECS框架编写单元测试?

    rust - 为实现特定类型的 trait 的泛型类型实现 trait

    rust - 如何在 Rust 中定义关联的 const 或类型别名?

    python - rust 中 ndarray::Array1<f64> 中的元素比较