【问题标题】:expected trait object `dyn Responsability`, found type parameter `T`预期特征对象`dyn Responsability`,找到类型参数`T`
【发布时间】:2022-01-20 21:55:30
【问题描述】:

我正在尝试在 Rust 中实现责任链:

link to playground

use std::error::Error;

struct Query {
    query: String,
}

struct Response {
    response: u64,
}

trait Responsability {
    fn take(&self, iterator: std::slice::Iter<Box<dyn Responsability>>, query: Query) -> Result<Response, Box<dyn Error>>;
}

struct ResponsabilityChain<T: Responsability> {
    responsabilities: Vec<Box<T>>,
}

impl<T: Responsability> ResponsabilityChain<T>
where
    T: Responsability,
{
    pub fn new(responsabilities: Vec<T>) -> Self {
        let responsabilities = responsabilities.into_iter()
            .map(|elt| Box::new(elt))
            .collect();
        
        Self { responsabilities }
    }
    
    pub fn launch(&self, query: Query) -> Result<Response, Box<dyn Error>> {
        let iterator = self.responsabilities.iter();
        let responsability = iterator.next().unwrap();
        
        responsability.take(iterator, query)
    }
}

fn main() {
    println!("Hello, world!");
}

臭名昭著的消息是:

编译 Playground v0.0.1 (/playground) 错误[E0308]:不匹配 类型 --> src/main.rs:35:29 | 19 | impl 责任链 | - 这个类型的参数... 35 |
responsability.take(迭代器,查询)|
^^^^^^^^ 预期特征对象dyn Responsability,找到类型 参数T | = 注意:预期结构 std::slice::Iter&lt;'_, Box&lt;(dyn Responsability + 'static)&gt;&gt; 找到 struct std::slice::Iter&lt;'_, Box&lt;T&gt;&gt; = help: 类型参数必须被约束以匹配其他类型 = 注意: 欲了解更多信息,请访问 https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

有关此错误的更多信息,请尝试rustc --explain E0308。 错误:由于先前的错误,无法编译playground

我不明白为什么编译器抱怨期待Box&lt;dyn Responsability&gt; 而拥有Box&lt;T&gt;,因为我指定了T: Responsability。我做错了什么?

【问题讨论】:

    标签: rust trait-objects


    【解决方案1】:

    dyn I 和 &lt;T&gt; where T: I 在 Rust 中是不同的类型,因此编译器会报错,因为没有隐式转换。

    T 是在编译时确定的具体类型。 dyn I 它是一个“特征对象”,它是动态的,具体类型未知,但有点包含在其中。

    关于该主题的good video。

    从&lt;T&gt; where T: I 到dyn I 的转换不是免费的,它有运行时成本,所以必须明确Rust 的理念。

    可以通过在所有地方使用Vec&lt;Box&lt;dyn Responsability&gt;&gt; 来修复代码。它还允许您将任意类型传递给new(),这可能是您想要的,因为Vec&lt;T&gt; 必须包含相同类型的对象(请记住,此类型是在编译时确定的)。

    【讨论】:

    • 我可以找到解决方法,但我遇到了 Box 问题。谢谢你的回答。
    • 根据你写的,我发现a working solution虽然最初比我简单得多。非常感谢您的解释,清澈如淡水。
    猜你喜欢
    • 2022-11-20
    • 1970-01-01
    • 1970-01-01
    • 2020-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多