You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>();
     }
  }
}

问题点:

  1. Rust 无法创建仅包含类型的向量——类型不占用内存空间,无法作为值存储;
  2. 即便能存储,迭代得到的实例也无法直接作为泛型参数传递给 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 10:44:56