我如何获得 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
的要求,它仍然无法正常工作。第一个问题是 A
在 Box<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/