【问题标题】:How do I cast Rc<RefCell<ConcreteType>> to Rc<RefCell<dyn Trait>>?如何将 Rc<RefCell<ConcreteType>> 转换为 Rc<RefCell<dyn Trait>>?
【发布时间】:2021-04-06 06:24:45
【问题描述】:

我正在尝试将 Rc&lt;RefCell&lt;Data&gt;&gt; 转换为 Rc&lt;RefCell&lt;dyn Interface&gt;&gt;(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

playground

【问题讨论】:

  • 与 Java 等语言不同,转换为 trait 对象实际上会修改数据(必须添加 vtable),这意味着您必须借用 refcell。
  • 转换值不仅仅是重新解释类型,因此您必须实际借用 RefCell 才能改变值。
  • 问题是通常,结构只包含它们的数据。例如,struct Foo { field: u8 } 的大小为 1 个字节。但是,为了将我们的对象用作 trait 对象(将其视为实现 trait 的随机对象),我们现在必须将其存储在一个描述如何使用它的函数表中,称为 vtable。 vtable 只是一个指向我们实现 trait 的表。
  • 假设我们有一个特征MyTrait 和一个方法run(),我们有结构Foo 和Bar 实现MyTrait,然后我们有一个包含许多@ 的Vec&lt;Box&lt;dyn MyTrait&gt;&gt; 987654336@s 和Bars。每个 trait 对象 (dyn MyTrait) 必须包含一个指向它的 run() 版本的指针,所以我们知道如何调用它。回到这个问题,问题是你需要存储一个指向特征中所有方法的指针表才能使用它。

标签: generics rust trait-objects


【解决方案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);
}

谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多