rust - "Expected trait A, found &A"尝试装箱特征对象时

标签 rust trait-objects

我正在尝试创建一个特征,它可以检索(并返回对另一个特征的特征对象的引用),或者创建一个特征(并返回它的盒装版本),将选择权留给实现者(意味着我需要将返回对象的生命周期限制为生产者的生命周期)。但是,我遇到了错误:

use std::borrow::Borrow;
use std::collections::HashMap;

trait A { 
    fn foobar(&self) {
        println!("!"); 
    } 
}

trait ProducerOrContainer {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<Box<dyn A + 'a>>;
}

impl<'b, B: Borrow<A>> ProducerOrContainer for HashMap<&'b str, B> {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<Box<dyn A + 'a>> {
        self.get(name).map(|borrow| Box::new(borrow.borrow()))
    }
}

错误是:

error[E0308]: mismatched types
  --> src/main.rs:20:9
   |
20 |         self.get(name).map(|borrow| Box::new(borrow.borrow()))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait A, found &A
   |
   = note: expected type `std::option::Option<std::boxed::Box<dyn A + 'a>>`
              found type `std::option::Option<std::boxed::Box<&dyn A>>`

这让我很困惑,因为我期待一个 &A成为A也。我试过 impl<'a> A for &'a A ,但这也无济于事。有什么办法可以解决这个问题吗?

最佳答案

...that can either retrieve (and return a reference to) a trait object of another trait, or create one (and return a boxed version of it).

根据此要求,Box 将不起作用。 Box 拥有它的数据,但有时您会借用无法移动的数据。

标准库中有一个类型叫做Cow ,这是对值是借用还是拥有的抽象。但是,它在这里可能不太适合您,因为它不会让您拥有作为 Box 的数据,并且还要求您的数据类型必须实现 ToOwned

但我们可以将您的要求直接建模为enum:

enum BoxOrBorrow<'a, T: 'a + ?Sized> {
    Boxed(Box<T>),
    Borrowed(&'a T),
}

并通过实现 Deref 使其符合人体工学:

use std::ops::Deref;

impl<'a, T> Deref for BoxOrBorrow<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        match self {
            BoxOrBorrow::Boxed(b) => &b,
            BoxOrBorrow::Borrowed(b) => &b,
        }
    }
}

这让您可以将自定义 BoxOrBorrow 类型视为任何其他引用 - 您可以使用 * 取消引用它或将它传递给任何需要引用 的函数T.

这就是您的代码的样子:

trait ProducerOrContainer {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>>;
}

impl<'b, B: Borrow<dyn A>> ProducerOrContainer for HashMap<&'b str, B> {
    fn get_a<'a>(&'a self, name: &'a str) -> Option<BoxOrBorrow<'a, dyn A + 'a>> {
        self.get(name)
            .map(|b| BoxOrBorrow::Borrowed(b.borrow()))
    }
}

关于rust - "Expected trait A, found &A"尝试装箱特征对象时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52353085/

相关文章:

generics - 为什么 `&(?Sized + Trait)`无法转换为 `&dyn Trait`?

rust - 我应该如何描述泛型类型的生命周期关系?

Rust,特征绑定(bind)选项未使用 process::Command 定义

multidimensional-array - 如何编写一个将 ndarray Array 或 ArrayView 作为输入的通用函数?

generics - 如何在Rust中创建对通用特征对象的引用的Vec? [复制]

types - 所有特征对象的默认特征方法实现

rust - `.map(f)` 和 `.map(|x| f(x))` 有什么区别?

rust - 除非我使用临时变量,否则为什么我不能插入 Vec 的 dyn Trait?

file - Rust:文件中字符串的生命周期

data-structures - Rust 自定义数据类型中的大小类型参数?