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

Rust中如何实现容纳不同嵌套泛型/trait对象的Processor的Vec?

多输入类型Processor的统一调度实现问题

我正在尝试实现一种模式,让不同的Processor可以指定自身接收的输入类型,并生成统一的输出(当前为固定类型,完成当前实现后计划将其泛型化)。

最小示例代码

use std::convert::From;

use processor::NoOpProcessor;

use self::{
    input::{Input, InputStore},
    output::UnifiedOutput,
    processor::{MultiplierProcessor, Processor, StringProcessor},
};

mod input {
    use std::collections::HashMap;

    #[derive(Debug)]
    pub struct Input<T>(pub T);

    #[derive(Default)]
    pub struct InputStore(HashMap<String, String>);

    impl InputStore {
        pub fn insert<K, V>(mut self, key: K, value: V) -> Self
        where
            K: ToString,
            V: ToString,
        {
            let key = key.to_string();
            let value = value.to_string();
            self.0.insert(key, value);

            self
        }

        pub fn get<K, V>(&self, key: K) -> Option<Input<V>>
        where
            K: ToString,
            for<'a> &'a String: Into<V>,
        {
            let key = key.to_string();
            self.0.get(&key).map(|value| Input(value.into()))
        }
    }
}

mod processor {
    use super::{input::Input, output::UnifiedOutput};

    use super::I32Input;

    pub struct NoOpProcessor;

    pub trait Processor {
        type I;
        fn process(&self, input: &Input<Self::I>) -> UnifiedOutput;
    }

    impl Processor for NoOpProcessor {
        type I = I32Input;
        fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
            UnifiedOutput(input.0 .0)
        }
    }

    pub struct MultiplierProcessor(pub i32);

    impl Processor for MultiplierProcessor {
        type I = I32Input;
        fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
            UnifiedOutput(input.0 .0 * self.0)
        }
    }

    pub struct StringProcessor;

    impl Processor for StringProcessor {
        type I = String;
        fn process(&self, input: &Input<Self::I>) -> UnifiedOutput {
            UnifiedOutput(input.0.parse().unwrap())
        }
    }
}

mod output {
    #[derive(Debug)]
    pub struct UnifiedOutput(pub i32);
}

pub fn main() {
    let input_store = InputStore::default()
        .insert("input_a", 123)
        .insert("input_b", 567)
        .insert("input_c", "789");

    let processors = {
        let mut labelled_processors = Vec::new();
        // let mut labelled_processors: Vec<LabelledProcessor<Input<>>> = Vec::new(); // What's the correct type?
        labelled_processors.push(LabelledProcessor("input_a", Box::new(NoOpProcessor)));
        labelled_processors.push(LabelledProcessor(
            "input_b",
            Box::new(MultiplierProcessor(3)),
        ));
        // labelled_processors.push(LabelledProcessor("input_c", Box::new(StringProcessor)));

        labelled_processors
    };

    for processor in processors {
        let output = retrieve_input_and_process(&input_store, processor);
        println!("{:?}", output);
    }
}

#[derive(Debug)]
pub struct I32Input(pub i32);

impl From<&String> for I32Input {
    fn from(s: &String) -> Self {
        Self(s.parse().unwrap())
    }
}

struct LabelledProcessor<I>(&'static str, Box<dyn Processor<I = I>>)
where
    for<'a> &'a String: Into<I>;

fn retrieve_input_and_process<T>(
    store: &InputStore,
    processor: LabelledProcessor<T>,
) -> UnifiedOutput
where
    for<'a> &'a String: Into<T>,
{
    let input = store.get(processor.0).unwrap();
    processor.1.process(&input)
}

编译错误信息

当取消注释// labelled_processors.push(LabelledProcessor("input_c", Box::new(StringProcessor)));时,会触发以下编译错误:

error[E0271]: type mismatch resolving `<attempt2::processor::StringProcessor as attempt2::processor::Processor>::I == attempt2::I32Input`
   --> src/attempt2.rs:101:63
    |
101 |         labelled_processors.push(LabelledProcessor("input_c", Box::new(StringProcessor)));
    |                                                               ^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<attempt2::processor::StringProcessor as attempt2::processor::Processor>::I == attempt2::I32Input`
    |
note: expected this to be `attempt2::I32Input`
   --> src/attempt2.rs:75:18
    |
75  |         type I = String;
    |                  ^^^^^^
    = note: required for the cast from `attempt2::processor::StringProcessor` to the object type `dyn attempt2::processor::Processor<I = attempt2::I32Input>`

问题分析与困惑

我清楚问题所在:labelled_processors这个Vec要求所有元素的类型必须相同,但我不知道该如何解决。我尝试过进一步利用动态调度(比如把LabelledProcessor改成struct LabelledProcessor(&'static str, Box<dyn Processor<dyn Input>>);),但这类修改又引发了其他类型系统问题。

网上找到的其他答案通常只涉及let vec_x: Vec<Box<dyn SomeTrait>>这类基础动态调度场景,没有覆盖这种嵌套泛型/trait对象的复杂情况。这让我怀疑是不是有什么简单的解决方案被我遗漏了,或者是否需要采用完全不同的模式来实现目标。

我知道可以用枚举,但这意味着所有用例都必须在同一个模块内定义,无法在外部模块中扩展输入、输出和Processor。现在我有些困惑。

--- 补充说明 ---

  • 这只是一个示例,InputStore将所有内容转换为String只是实现细节,核心是要体现“类型需符合某trait才能被接受”的概念,选择String只是为了简化。

内容的提问来源于stack exchange,提问作者Clown

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:15:41