Rust中如何批量构建不同Props类型实例(替代类型向量方案)
问题描述
现有可运行的简化代码如下:
pub trait Props { // ... } // One、Two 和 Three 均实现了 Props trait pub type One = LengthyServiceDefWithGenerics<...>; pub type Two = AnotherServiceDefWithGenerics<...>; pub type Three = YetAnother<...>; impl Builder { pub fn build_it<P: Props>(&self) -> Elem<P> { Elem::new(self); } } // 代码库其他位置 // 可能需要构建的实例不止 a、b、c let builder = Builder.new(); let a = builder.build_it::<One>(); let b = builder.build_it::<Two>(); let c = builder.build_it::<Three>();
作为 Rust 新手,尝试用以下代码抽象批量构建逻辑,但存在核心问题:
impl Outer { pub fn new(props: Vec<Props>) { let builder = Builder::new(); for p in props.iter() { builder.build_it::<p>(); } } }
问题点:
- Rust 无法创建仅包含类型的向量——类型不占用内存空间,无法作为值存储;
- 即便能存储,迭代得到的实例也无法直接作为泛型参数传递给
build_it。
需要找到可行的批量构建实现方式。
可行实现方案
方案一:宏批量生成代码(编译期固定类型)
如果需要构建的类型是编译期已知的固定集合,用 Rust 宏可以避免重复书写调用代码,无运行时开销:
macro_rules! build_all { ($builder:expr, $($ty:ty),*) => { vec![ $( $builder.build_it::<$ty>(), )* ] }; } // 使用示例 let builder = Builder::new(); let elems = build_all!(builder, One, Two, Three);
方案二:Trait 对象 + 工厂函数(运行时动态类型)
如果需要在运行时动态添加要构建的类型,可以定义工厂 trait,用空类型标记携带类型信息:
// 定义工厂 trait,负责创建对应类型的 Elem trait ElemFactory { fn create(&self, builder: &Builder) -> Box<dyn std::any::Any>; } // 为所有实现 Props 的类型自动生成工厂实现 // PhantomData 不占用内存,仅用于标记类型 impl<P: Props + 'static> ElemFactory for std::marker::PhantomData<P> { fn create(&self, builder: &Builder) -> Box<dyn std::any::Any> { Box::new(builder.build_it::<P>()) } } // 重构后的 Outer::new impl Outer { pub fn new(factories: Vec<Box<dyn ElemFactory>>) { let builder = Builder::new(); for factory in factories { let elem = factory.create(&builder); // 此处可对 elem 做后续处理,比如存入集合 } } } // 调用示例 let factories = vec![ Box::new(std::marker::PhantomData::<One>), Box::new(std::marker::PhantomData::<Two>), Box::new(std::marker::PhantomData::<Three>), ]; Outer::new(factories);
后续若需要还原具体类型,可通过 Any trait 的 downcast 方法实现。
方案三:编译期类型列表(无运行时开销)
如果想要编译期动态的类型集合,可自定义类型列表 trait:
// 定义类型列表 trait trait TypeList { fn build_all(&self, builder: &Builder) -> Vec<Box<dyn std::any::Any>>; } // 空列表实现 impl TypeList for () { fn build_all(&self, _builder: &Builder) -> Vec<Box<dyn std::any::Any>> { Vec::new() } } // 递归实现类型列表的构建逻辑 impl<P: Props + 'static, Rest: TypeList> TypeList for (P, Rest) { fn build_all(&self, builder: &Builder) -> Vec<Box<dyn std::any::Any>> { let mut elems = self.1.build_all(builder); elems.insert(0, Box::new(builder.build_it::<P>())); elems } } // 使用示例 let builder = Builder::new(); let type_list = (One, (Two, (Three, ()))); let elems = type_list.build_all(&builder);
该方案完全在编译期展开逻辑,无运行时开销,但写法相对繁琐。
内容的提问来源于stack exchange,提问作者unsafe_where_true
相关产品推荐
相关产品推荐

