rust - 如何从特征对象中获取对具体类型的引用?

标签 rust traits

我如何获得 Box<B>&B&Box<B>来自 a此代码中的变量:

trait A {}

struct B;
impl A for B {}

fn main() {
    let mut a: Box<dyn A> = Box::new(B);
    let b = a as Box<B>;
}

此代码返回错误:

error[E0605]: non-primitive cast: `std::boxed::Box<dyn A>` as `std::boxed::Box<B>`
 --> src/main.rs:8:13
  |
8 |     let b = a as Box<B>;
  |             ^^^^^^^^^^^
  |
  = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait

最佳答案

在 Rust 中有两种方法可以进行向下转换。第一种是使用 Any .请注意,这只允许您向下转换为确切的原始具体类型。像这样:

use std::any::Any;

trait A {
    fn as_any(&self) -> &dyn Any;
}

struct B;

impl A for B {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

fn main() {
    let a: Box<dyn A> = Box::new(B);
    // The indirection through `as_any` is because using `downcast_ref`
    // on `Box<A>` *directly* only lets us downcast back to `&A` again.
    // The method ensures we get an `Any` vtable that lets us downcast
    // back to the original, concrete type.
    let b: &B = match a.as_any().downcast_ref::<B>() {
        Some(b) => b,
        None => panic!("&a isn't a B!"),
    };
}

另一种方法是为基本特征上的每个“目标”(在本例中为 A)实现一个方法,并为每个所需的目标类型实现强制转换。

等等,我们为什么需要 as_any ?

即使您添加 Any作为 A 的要求,它仍然无法正常工作。第一个问题是 ABox<dyn A>还将实现Any ... 表示当您调用 downcast_ref 时,您实际上会在对象类型 A 上调用它. Any只能向下转换为调用它的类型,在本例中为 A , 所以你只能回退到 &dyn A你已经拥有了。

但是有一个 Any 的实现对于那里的底层类型,对吧?嗯,是的,但你无法做到这一点。 Rust 不允许你从 &dyn A “交叉转换”至&dyn Any .

这就是 as_any是为了;因为它只在我们的“具体”类型上实现,所以编译器不会混淆它应该调用哪一个。调用&dyn A导致它动态分派(dispatch)到具体实现(同样,在本例中为 B::as_any ),它返回一个 &dyn Any使用 Any 的实现对于 B ,这就是我们想要的。

请注意,您可以通过不使用 A 来回避整个问题。一点也不。具体来说,以下内容也将起作用:
fn main() {
    let a: Box<dyn Any> = Box::new(B);
    let _: &B = match a.downcast_ref::<B>() {
        Some(b) => b,
        None => panic!("&a isn't a B!")
    };    
}

但是,这使您无法使用任何其他方法;您在这里所能做的就是向下转换为具体类型。

作为潜在利益的最后说明,mopa crate 允许您组合 Any 的功能有你自己的特点。

关于rust - 如何从特征对象中获取对具体类型的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65236836/

相关文章:

SslStream<TcpStream> 读取不返回客户端的消息

arrays - 如何在Rust中不同大小的数组之间复制?

rust - 如何处理我从 HashMap 获得的值

php - 未找到 Laravel 自定义特征

rust - 特征和关联类型

multidimensional-array - 如何过滤掉 ndarray 中的特定列?

stream - 返回 Stream 特征对象的 Future

ruby-on-rails - 编写无效的 FactoryGirl 工厂/特征是个坏主意吗?

scala - 与 IO monads 的普通旧特征相比,Free monads 有什么优势?

rust - 如何在 Rust 中获取向量中的最小值?