提问人:Lomírus 提问时间:11/3/2023 更新时间:11/3/2023 访问量:53
按元素类型过滤向量
Filter vector by element type
问:
有没有办法实现下面的功能?
trait X {}
struct A;
struct B;
impl X for A {}
impl X for B {}
/// Only keep elements of type A
fn filter(list: Vec<Box<dyn X>>) -> Vec<Box<A>> {
todo!();
}
在 dart 中,它可能要容易得多:
List<A> filter(list: List<X>) {
return list.whereType<A>();
}
答:
3赞
Chayim Friedman
11/3/2023
#1
你需要使用某种向下的解释。如How to get a reference to a concrete type from a trait object?中所述,稳定的方法是添加一个方法:as_any()
use std::any::Any;
trait X {
fn as_any_box(self: Box<Self>) -> Box<dyn Any>;
}
struct A;
struct B;
impl X for A {
fn as_any_box(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl X for B {
fn as_any_box(self: Box<Self>) -> Box<dyn Any> {
self
}
}
/// Only keep elements of type A
fn filter(list: Vec<Box<dyn X>>) -> Vec<Box<A>> {
list.into_iter()
.filter_map(|v| v.as_any_box().downcast::<A>().ok())
.collect()
}
3赞
Aleksander Krauze
11/3/2023
#2
Chayim 对你的确切问题给出了很好的答案,但我想补充一点,如果你能够稍微改变你的要求并使用枚举调度而不是动态调度,你的问题将变得微不足道。
use std::iter::Extend;
trait X {}
struct A;
struct B;
impl X for A {}
impl X for B {}
enum DispatchX {
A(A),
B(B),
}
impl X for DispatchX {
// delegate all X's methods to present variant
}
fn filterA(list: Vec<DispatchX>) -> Vec<A> {
let mut result = Vec::with_capacity(list.len());
let data = list
.into_iter()
.filter_map(|x| {
match x {
DispatchX::A(a) => Some(a),
_ => None,
}});
result.extend(data);
data
}
您可以使用板条箱enum_dispatch自动创建。当然,只有当特征的实现者有限,并且所有实现者都是你的板条箱的本地实现者(或者至少你不希望你的任何消费者创建一个)时,这才有效。DispatchX
X
另请注意,我没有选择迭代器,而是扩展先前分配的向量。这将导致不会重新分配,但如果 中的项目很少,则分配的内存可能会比您需要的多得多。如果 s 与 s 的比率是可预测的,则可以操作给定的容量以提高内存使用率。collecting
A
list
A
B
Vec::with_capacity
上一个:无法为整数类型实现泛型 FN
评论