如果 A == B<A>,则将 Rc<B> 向下转换为 Rc

问题描述 投票:0回答:1

我想知道以下代码是否有效(也许有一种内置/安全的方法可以将

Rc<dyn SomeTrait>
向下转换为
Rc<SomeType>
?我找不到任何方法),最重要的是,它安全吗?

use std::any::*;
use std::rc::*;

// NOTE: apparently adding Any here is REQUIRED
//       otherwise it doesn't work at all,
//       I have no idea why
trait SomeTrait: Any {}
struct SomeType;

impl SomeTrait for SomeType {}

fn rc_downcaster<A: 'static, B: ?Sized + 'static>(b: Rc<B>) -> Option<Rc<A>> {
    if Any::type_id(&*b) == TypeId::of::<A>() {
        Some(unsafe {
            let p = Rc::into_raw(b);
            Rc::from_raw(p as *const A)
        })
    } else {
        None
    }
}


fn main() {
    let x: Rc<dyn SomeTrait> = Rc::new(SomeType);
    let _: Rc<SomeType> = rc_downcaster(x).unwrap();
}

游乐场

rust unsafe
1个回答
3
投票

在不使用 nightly 的情况下,我找到了这个安全的替代解决方案:

use std::any::*;
use std::rc::*;

trait SomeTrait: AsAny {}
struct SomeType;

impl SomeTrait for SomeType {}

trait AsAny {
    fn as_any(self: Rc<Self>) -> Rc<dyn Any>;
}

impl<T: 'static> AsAny for T {
    fn as_any(self: Rc<Self>) -> Rc<dyn Any> where Self: Sized
    {
        self
    }
}

fn main() {
    let x: Rc<SomeType> = Rc::new(SomeType);
    let x: Rc<dyn Any> = x.as_any();
    let _: Rc<SomeType> = Rc::downcast(x).unwrap();
}

但值得一提@cafce25的解决方案(在评论中):

如果您在 nightly 上,则可以使用 Rc::downcast 并添加 #![feature(trait_upcasting)]。既然这样,你的代码也应该是健全的。 游乐场

© www.soinside.com 2019 - 2024. All rights reserved.