如何从特征对象获取对具体类型的引用? [英] How to get a reference to a concrete type from a trait object?
问题描述
我如何从 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
中的 A
将 also 实现 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 Any
将 Any
的实现用于 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屋!