【发布时间】:2021-04-06 06:24:45
【问题描述】:
我正在尝试将 Rc<RefCell<Data>> 转换为 Rc<RefCell<dyn Interface>>(Data 实现 Interface)但在通用方法中这是不可能的:
use std::cell::RefCell;
use std::rc::Rc;
trait Interface {
fn pouet(&self);
}
struct Data {}
impl Interface for Data {
fn pouet(&self) {
println!("pouet");
}
}
fn helper<T>(o: &Rc<RefCell<T>>)
where
T: Interface,
{
let t = o as &Rc<RefCell<dyn Interface>>;
work(t);
}
fn work(o: &Rc<RefCell<dyn Interface>>) {
o.borrow().pouet();
}
fn main() {
// work
{
let o = Rc::new(RefCell::new(Data {}));
work(&(o as Rc<RefCell<dyn Interface>>));
}
// raise an compile error
{
let o = Rc::new(RefCell::new(Data {}));
helper(&o);
}
}
我在 non-primitive cast 上有一个编译错误:
error[E0605]: non-primitive cast: `&Rc<RefCell<T>>` as `&Rc<RefCell<dyn Interface>>`
--> src/main.rs:20:13
|
20 | let t = o as &Rc<RefCell<dyn Interface>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
【问题讨论】:
-
与 Java 等语言不同,转换为 trait 对象实际上会修改数据(必须添加 vtable),这意味着您必须借用 refcell。
-
转换值不仅仅是重新解释类型,因此您必须实际借用 RefCell 才能改变值。
-
问题是通常,结构只包含它们的数据。例如,
struct Foo { field: u8 }的大小为 1 个字节。但是,为了将我们的对象用作 trait 对象(将其视为实现 trait 的随机对象),我们现在必须将其存储在一个描述如何使用它的函数表中,称为 vtable。 vtable 只是一个指向我们实现 trait 的表。 -
假设我们有一个特征
MyTrait和一个方法run(),我们有结构Foo和Bar实现MyTrait,然后我们有一个包含许多@ 的Vec<Box<dyn MyTrait>>987654336@s 和Bars。每个 trait 对象 (dyn MyTrait) 必须包含一个指向它的run()版本的指针,所以我们知道如何调用它。回到这个问题,问题是你需要存储一个指向特征中所有方法的指针表才能使用它。
标签: generics rust trait-objects