Rust 如何筛选铁锈中特定子序列的RCed特征对象向量?
任务是筛选出基本特征对象向量的supertrait对象: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
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()) {
// ...
}