Rust 如何筛选铁锈中特定子序列的RCed特征对象向量?

Rust 如何筛选铁锈中特定子序列的RCed特征对象向量?,rust,casting,ownership,rc,Rust,Casting,Ownership,Rc,任务是筛选出基本特征对象向量的supertrait对象: use std::rc::Rc; use std::any::Any; pub trait TraitA { fn get_title(&self) -> &str; fn as_any(&self) -> Any; } pub trait TraitB: TraitA { fn get_something(&self) -> &str; } pub

任务是筛选出基本特征对象向量的supertrait对象:

use std::rc::Rc;
use std::any::Any;

pub trait TraitA {
    fn get_title(&self) -> &str;
    fn as_any(&self) -> Any;
}

pub trait TraitB: TraitA {
    fn get_something(&self) -> &str;
}

pub fn filter_b(input: Vec<Rc<dyn TraitA>>) -> Vec<Rc<dyn TraitB>> {
    // bs.filter(|it| /* How to do it? */).collect();
}
使用std::rc::rc;
使用std::any::any;
酒馆特拉塔酒店{
fn获取标题(&self)->&str;
fn as_any(&self)->any;
}
酒馆特征TraitB:TraitA{
fn获得某物(&self)->&str;
}
pub fn filter_b(输入:Vec)->Vec{
//bs.filter(| it |/*如何做?*/).collect();
}
有可能吗?有什么线索或建议吗


我知道
as_any()
可以用于downcast,但我不确定它是如何与
Rc
一起工作的,因为它拥有所有权(因此需要实例)。

我最初希望答案是“绝对不!”,
如果你不知道具体的类型,
any
没有帮助。但事实证明你可以。。。有警告,但我不能100%确定它是否完全安全

要从
Rc
转到
Rc
,可以使用逃生舱口和。前者的文件如下:

从原始指针构造Rc

原始指针之前必须通过调用
Rc::into_raw
返回,其中
U
的大小和对齐方式必须与
T
相同。如果
U
T
,则这是非常正确的。请注意,如果
U
不是
T
,而是具有相同的大小和对齐方式,这基本上类似于转换不同类型的引用。有关在这种情况下适用的限制的更多信息,请参阅

来自_raw
用户必须确保只删除一次
T
的特定值

此函数不安全,因为使用不当可能导致内存不安全,即使从未访问返回的
Rc

考虑到这一点,因为我们只能访问
TraitA
,所以它需要一个
as_b()
函数来将自身作为
TraitB
。事实上,目标是一个超级特质并没有真正的帮助。然后我们可以编写一个
crosscast
函数,如下所示:

use std::rc::Rc;

trait TraitA {
    fn print_a(&self);

    // SAFETY: the resulting `dyn TraitB` must have the *exact* same address,
    // size, alignment, and drop implementation for `crosscast` to work safely.
    // Basically it must be `self` or maybe a transparently wrapped object.
    unsafe fn as_b(&self) -> Option<&(dyn TraitB + 'static)>;
}

trait TraitB {
    fn print_b(&self);
}

fn crosscast(a: Rc<dyn TraitA>) -> Option<Rc<dyn TraitB>> {
    unsafe {
        let b_ptr = a.as_b()? as *const dyn TraitB;
        let a_ptr = Rc::into_raw(a);
        
        // sanity check
        assert!(a_ptr as *const () == b_ptr as *const ());
        
        Some(Rc::from_raw(b_ptr))
    }
}
一起看电视

如果可能的话,我仍然建议不要这样做。例如,使用上述方法从
&Rc
转到
选项
,不受所有限制,这将是非常安全的。这样的东西不会有限制和不安全:

for b in vec_a.iter().filter_map(|a| a.as_b()) {
   // ...
}

那可能有用,谢谢。然而,Rust被宣布为没有价格抽象,如果可能的话,我希望有一个安全的解决方案(即使代价是对traits或impls添加一些修改)。顺便说一句,我不确定你是否注意到,
TraitB:TraitA
很重要。这是否使任务变得更简单了?“Rust被声明为没有价格抽象”-我不确定你在这里想说什么,这里的语言没有强加任何“成本”。是
Rc
强加了这些要求,而且几乎没有运行时成本。如果每个
A
都是
B
,这可能更直截了当,但如果它是有条件的,则必须有某种东西指示该条件,因此有打破
Rc
s不变量的空间
TraitB:TraitA
不建立从
a
B
的关系。这可能更难打破,因此在即将到来的专业化中更安全,但我还没有探讨过这一点。
for b in vec_a.iter().filter_map(|a| a.as_b()) {
   // ...
}