如何将Rc<RefCell<ConcreteType>>转换为Rc<RefCell<dyn Trait>>?

4

我正在尝试将 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);
    }
}

我在非原始类型转换上遇到了编译错误:

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

playground


3
与Java等语言不同,强制转换为trait对象实际上会修改数据(必须添加vtable),这意味着您必须借用refcell。 - Aplet123
1
强制类型转换并不仅仅是重新解释类型,因此您必须实际借用RefCell以便可以改变该值。 - Aplet123
2
问题在于通常情况下,结构体只包含它们的数据。例如,struct Foo { field: u8 } 的大小为1个字节。然而,为了将我们的对象用作特质对象(将其视为实现特质的某个随机对象),我们现在必须将其存储在一个描述如何使用它的函数表中,称为vtable。vtable只是一个指向我们特质实现的表。 - Coder-256
1
假设我们有一个带有方法run()的特质MyTrait,我们有实现MyTrait的结构体FooBar,然后我们有一个包含许多FooBarVec<Box<dyn MyTrait>>。每个特质对象(dyn MyTrait)必须包含指向其版本的run()的指针,以便我们知道如何调用它。所以回到问题,问题是您需要存储指向特质中所有方法的指针表,以便能够使用它。 - Coder-256
2
是的,因为o只是指向Data实例的指针,而你想让它成为dyn Interface实例。dyn Interface由vtable和“实际”类型组成(因此在此情况下,它由vtable加上Data实例组成)。一种看法是:你有一个指向Data的指针,并试图将其强制转换为指向dyn Interface的指针(即vtable加上Data),所以当然会失败,因为它们不相同。 - Coder-256
显示剩余8条评论
1个回答

1
许多感谢,我理解。
解决方案是:
fn helper<T>(o: &Rc<RefCell<T>>)
where
    T: Interface + 'static,
{
    let t = o.clone() as Rc<RefCell<dyn Interface>>;
    work(&t);
}

或者

fn helper<T>(o: Rc<RefCell<T>>)
where
    T: Interface + 'static,
{
    let t = o as Rc<RefCell<dyn Interface>>;
    work(&t);
}

谢谢


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接