首页 文章

Downcasting和Box <Any>

提问于
浏览
5
pub struct WidgetWrap {
    // ...
    widget: RefCell<Box<Any>>,
}

在某些时候我想将 Box<Any> 转换为 Box<WidgetTrait>

let mut cell = widget.borrow_mut();
let w = cell.downcast_mut::<Box<WidgetTrait>>();

这给了我这样的错误:

error: instantiating a type parameter with an incompatible type
`Box<WidgetTrait>`, which does not fulfill `'static` [E0144]

这究竟意味着什么?

我看了How to fix: value may contain references; add 'static bound to T,并尝试到处添加 + 'static .

pub struct WidgetWrap {
    // ...
    widget: RefCell<Box<Any + 'static>>,
}
let mut cell = widget.borrow_mut();
let w = cell.downcast_mut::<Box<WidgetTrait + 'static>>();

它修复了编译错误,但是当我尝试打开如下所示的downcasrap框时失败 . 是的,该框的内容是一个实现 WidgetTrait 的对象 .

显然,我在Rust中的编码水平我不太了解,但也许有人可以帮助我更好地掌握上述任务中涉及的概念 .

2 回答

  • 1

    (我将忽略 'static 部分,因为它与我正在解释的部分相比无关紧要 . )

    Box<Trait> 对于给定的特征 Trait 存储为两个数据:指向内存中实际数据的指针和指向vtable的指针,用于其类型的 Trait 实现 .

    从那里,你可能会发现你只能拥有一个级别的特权 - 如果你有一个 Box<WidgetTrait> 而你再次将它作为 Box<Any> ,你只能将它作为一个 Box<WidgetTrait> 对象 . 类似地,如果你采用一个实现 WidgetTraitWidget 类型并将其列入 Box<Any> ,你只能将其作为 Widget 对象而不是 Box<WidgetTrait> 对象 .

    这就是内部使用的类型ID的本质:与基于动态或基于VM的语言不同,类型系统纯粹是编译时构造;在运行时没有类型系统这样的东西 .

    解决方案,如果你真的需要这些方面的解决方案(你可能不这样做;只坚持 Box<WidgetTrait> 可能是最好的方法)就是有一个特性也可以实现 Any 的功能 . 这不是目前最简单的事情,但可以做到 . Teepee’s Header trait是一个如何运作的例子; Box<Header> 对象将具有标头转换方法以及 Any.downcast_ref() 等等 .

  • 11

    原始代码至少在Rust 1.25中工作;据推测,编译器中存在一个已修复的错误或限制:

    use std::any::Any;
    use std::cell::RefCell;
    
    trait WidgetTrait {}
    
    fn example(widget: RefCell<Box<Any>>) {
        let mut cell = widget.borrow_mut();
        let w = cell.downcast_mut::<Box<WidgetTrait>>();
    }
    
    fn main() {}
    

相关问题