如何从特征对象获取对具体类型的引用? [英] How to get a reference to a concrete type from a trait object?

查看:25
本文介绍了如何从特征对象获取对具体类型的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何从 a<获取 Box&B&Box/code> 此代码中的变量:

How do I get Box<B> or &B or &Box<B> from the a variable in this code:

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.请注意,这允许您向下转换为准确的原始具体类型.像这样:

There are two ways to do downcasting in Rust. The first is to use Any. Note that this only allows you to downcast to the exact, original concrete type. Like so:

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)实现一个方法,并为每个所需的目标类型实现强制转换.

The other way is to implement a method for each "target" on the base trait (in this case, A), and implement the casts for each desired target type.

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

即使您将 Any 添加为 A 的要求,它仍然无法正常工作.第一个问题是 Box 中的 Aalso 实现 Any... 意味着当您调用 downcast_ref 时,实际上是在对象类型 A 上调用它.Any 可以向下转换到它被调用的类型,在这种情况下是 A,所以你只能返回直到您已经拥有的 &dyn A.

Even if you add Any as a requirement for A, it's still not going to work correctly. The first problem is that the A in Box<dyn A> will also implement Any... meaning that when you call downcast_ref, you'll actually be calling it on the object type A. Any can only downcast to the type it was invoked on, which in this case is A, so you'll only be able to cast back down to &dyn A which you already had.

但是有一个Any 的实现,用于某处 中的底层类型,对吗?嗯,是的,但你不能理解它.Rust 不允许你从 &dyn A&dyn Any 的交叉转换".

But there's an implementation of Any for the underlying type in there somewhere, right? Well, yes, but you can't get at it. Rust doesn't allow you to "cross cast" from &dyn A to &dyn Any.

就是 as_any 的用途;因为它只在我们的具体"类型上实现,所以编译器不会混淆它应该调用哪个类型.在 &dyn A 上调用它会导致它动态分派到具体实现(同样,在这种情况下,B::as_any),它返回一个 &dyn AnyAny 的实现用于 B,这正是我们想要的.

That is what as_any is for; because it's something only implemented on our "concrete" types, the compiler doesn't get confused as to which one it's supposed to invoke. Calling it on an &dyn A causes it to dynamically dispatch to the concrete implementation (again, in this case, B::as_any), which returns an &dyn Any using the implementation of Any for B, which is what we want.

请注意,您可以通过完全不使用A来回避整个问题.具体来说,以下内容有效:

Note that you can side-step this whole problem by just not using A at all. Specifically, the following will also work:

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!")
    };    
}

然而,这使您无法使用任何其他方法;所有你在这里可以做的是向下转型到一个具体的类型.

However, this precludes you from having any other methods; all you can do here is downcast to a concrete type.

作为潜在兴趣的最后一点,mopa crate 允许您结合 任何都有自己的特点.

As a final note of potential interest, the mopa crate allows you to combine the functionality of Any with a trait of your own.

这篇关于如何从特征对象获取对具体类型的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆