首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >锈铸超性状

锈铸超性状
EN

Stack Overflow用户
提问于 2022-11-29 14:45:16
回答 1查看 48关注 0票数 0

我有一个容器,可以存储实现CommonBase特性的项目,还有其他一些特性(例如,TypeATypeB,但也可以有未知数量的其他TypeX特征),CommonBase是它们的超级特征。我将实现ItemA的对象存储到容器中,我可以从容器中获得对项的引用,但作为对CommonBase的引用。

我想将该项目转换为原来的类型,如下所示:

代码语言:javascript
复制
fn cast_to<T: SuperTrait>(val: dyn CommonBase) -> Result<T, dyn Error> {...}

有人能帮忙吗?

这是我的实验代码

代码语言:javascript
复制
use std::error::Error;
use std::rc::Rc;

pub trait CommonBase {
    fn to_common(self: &Self);
}

pub trait TypeA: CommonBase {
    fn do_a(self: &Self);
}

pub trait TypeB: CommonBase {
    fn do_b(self: &Self);
}

pub struct StructA {}

impl CommonBase for StructA {
    fn to_common(self: &Self) { todo!() }
}

impl TypeA for StructA {
    fn do_a(self: &Self) { todo!() }
}


pub struct StructB {}

impl CommonBase for StructB {
    fn to_common(self: &Self) { todo!() }
}

impl TypeB for StructB {
    fn do_b(self: &Self) { todo!() }
}

pub struct Container {
    items: Vec<Rc<dyn CommonBase>>,
}


impl Container {
    pub fn new() -> Container {
        Container { items: Vec::new() }
    }

    pub fn add(self: &mut Self, item: Rc<dyn CommonBase>) {
        self.items.push(item);
    }

    pub fn get(self, idx: usize) -> Rc<dyn CommonBase> {
        self.items.get(idx).unwrap().clone()
    }
}

fn cast_to<T: CommonBase>(val: Rc<dyn CommonBase>) -> Result<Rc<dyn T>, Box<dyn Error>> {...}  // <- some magic is done here

fn main() {
    let mut container = Container::new();
    let item_a = Rc::new(StructA {});
    let item_b = Rc::new(StructB {});
    container.add(item_a);  // index 0
    container.add(item_b);  // index 1

    let stored_a_as_common: Rc<dyn CommonBase> = container.get_common(0);  // actually TypeA
    let stored_a: Rc<dyn TypeA> = cast_to(stored_a_as_common).unwrap();
    stored_a.do_a();
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-29 17:13:31

这是您的代码,并添加了一些内容。

为此,您需要std::any::Any。为了尝试动态强制转换,每个受动态强制转换的结构都应该被称为dyn Any;这就是本例中.as_any().as_any_mut()的目的。使用.downcast_ref().downcast_mut()需要目标是类型的,而不是特征。

我不认为同时有两个Rc指向相同的结构,但声明有不同的dyn特征。在我看来,最好的方法就是只处理引用(不管它们来自何处,Rc或其他东西)。

当不可能进行动态转换时,您希望得到一个Error,然后我以这种方式编写函数。但是请注意,.downcast_ref()返回一个Option,这通常是足够好的(None意味着转换是不可能的);我们可以只使用这一行val.as_any().downcast_ref::<T>()来简化代码。

代码语言:javascript
复制
use std::error::Error;
use std::rc::Rc;

use std::any::Any;

pub trait CommonBase: Any {
    fn to_common(self: &Self);
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

pub trait TypeA: CommonBase {
    fn do_a(self: &Self);
}

pub trait TypeB: CommonBase {
    fn do_b(self: &Self);
}

pub struct StructA {}

impl CommonBase for StructA {
    fn to_common(self: &Self) {
        todo!()
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

impl TypeA for StructA {
    fn do_a(self: &Self) {
        println!("doing a");
    }
}

pub struct StructB {}

impl CommonBase for StructB {
    fn to_common(self: &Self) {
        todo!()
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

impl TypeB for StructB {
    fn do_b(self: &Self) {
        println!("doing b");
    }
}

pub struct Container {
    items: Vec<Rc<dyn CommonBase>>,
}

impl Container {
    pub fn new() -> Container {
        Container { items: Vec::new() }
    }

    pub fn add(
        self: &mut Self,
        item: Rc<dyn CommonBase>,
    ) {
        self.items.push(item);
    }

    pub fn get(
        &self,
        idx: usize,
    ) -> Rc<dyn CommonBase> {
        self.items.get(idx).unwrap().clone()
    }
}

fn cast_to<T: CommonBase>(
    val: &dyn CommonBase
) -> Result<&T, Box<dyn Error>> {
    if let Some(t_ref) = val.as_any().downcast_ref::<T>() {
        Ok(t_ref)
    } else {
        Err("bad cast")?
    }
}

#[allow(dead_code)] // unused in this example
fn cast_to_mut<T: CommonBase>(
    val: &mut dyn CommonBase
) -> Result<&mut T, Box<dyn Error>> {
    if let Some(t_ref) = val.as_any_mut().downcast_mut::<T>() {
        Ok(t_ref)
    } else {
        Err("bad cast")?
    }
}

fn main() {
    let mut container = Container::new();
    let item_a = Rc::new(StructA {});
    let item_b = Rc::new(StructB {});
    container.add(item_a); // index 0
    container.add(item_b); // index 1

    let stored_a_as_common: Rc<dyn CommonBase> = container.get(0); // actually TypeA
    let stored_a: &dyn TypeA =
        cast_to::<StructA>(stored_a_as_common.as_ref()).unwrap();
    stored_a.do_a();

    let stored_b_as_common: Rc<dyn CommonBase> = container.get(1); // actually TypeB
    let stored_b: &dyn TypeB =
        cast_to::<StructB>(stored_b_as_common.as_ref()).unwrap();
    stored_b.do_b();
}
/*
doing a
doing b
*/
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74615823

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档