Rust如何编写可同时接受trait或其智能指针的泛型代码
实现方案
核心思路是通过Process trait的 blanket 自动转发实现,让Simulation泛型同时兼容具体进程类型、各类进程指针场景:
use std::ops::DerefMut; use std::pin::Pin; // 修正Process trait,补充实例方法必要的self参数 trait Process { fn start(&mut self); fn process_event(&mut self); } // 通用转发实现:所有能可变解引用到Process的类型自动实现Process trait // 天然覆盖Box<T>、Pin<Box<T>>、OwningRef等各类指针场景 impl<T: Process + ?Sized, P: DerefMut<Target = T>> Process for P { fn start(&mut self) { (**self).start() } fn process_event(&mut self) { (**self).process_event() } } // 泛型Simulation结构体,约束P必须实现Process struct Simulation<P: Process> { processes: Vec<P>, } impl<P: Process> Simulation<P> { fn add_process(&mut self, p: P) { self.processes.push(p); } fn run(&mut self) { for process in &mut self.processes { process.process_event(); // 其余模拟逻辑 } } }
三种使用场景
1. 静态分发(无动态开销,仅支持单一进程类型)
// 自定义进程实现 struct WorkerProcess { id: u32, } impl Process for WorkerProcess { fn start(&mut self) { println!("Worker {} 启动", self.id); } fn process_event(&mut self) { println!("Worker {} 处理事件", self.id); } } // 直接存储进程实例,无指针、无动态分发开销 let mut sim = Simulation { processes: Vec::new() }; sim.add_process(WorkerProcess { id: 1 }); sim.add_process(WorkerProcess { id: 2 }); sim.run();
2. 动态分发(支持多进程类型混合,使用Box指针)
// 另一种进程实现 struct IoProcess { name: String, } impl Process for IoProcess { fn start(&mut self) { println!("IO进程 {} 启动", self.name); } fn process_event(&mut self) { println!("IO进程 {} 处理事件", self.name); } } // 泛型参数指定为Box<dyn Process>,支持多类型进程混合存储 let mut sim: Simulation<Box<dyn Process>> = Simulation { processes: Vec::new() }; sim.add_process(Box::new(WorkerProcess { id: 3 })); sim.add_process(Box::new(IoProcess { name: "disk-io".to_string() })); sim.run();
3. 自引用进程场景(使用Pin指针)
// 自引用进程示例 struct SelfRefProcess { value: i32, self_ref: *const Self, } impl SelfRefProcess { fn new(v: i32) -> Pin<Box<Self>> { let mut inst = Box::pin(Self { value: v, self_ref: std::ptr::null(), }); let self_ptr = &*inst as *const Self; // 安全自引用赋值 unsafe { Pin::as_mut(&mut inst).get_unchecked_mut().self_ref = self_ptr; } inst } } impl Process for SelfRefProcess { fn start(&mut self) { println!("自引用进程启动,value: {}", self.value); } fn process_event(&mut self) { println!("自引用进程处理事件,value: {}", unsafe { (*self.self_ref).value }); } } // 泛型参数指定为Pin<Box<dyn Process>>,直接兼容自引用场景 let mut sim: Simulation<Pin<Box<dyn Process>>> = Simulation { processes: Vec::new() }; sim.add_process(SelfRefProcess::new(10)); sim.run();
补充说明
- 原示例中
Vec<dyn Process>的写法不合法,动态大小类型不能直接存在集合中,必须用指针包装,上述实现已解决该问题。 - 如果Process方法不需要修改进程状态,可以将
DerefMut替换为Deref,同时去掉方法的&mut修饰符即可。 - 静态分发场景完全零额外开销,动态分发场景和原有Box实现的开销一致。
内容的提问来源于stack exchange,提问作者Effie
相关产品推荐
相关产品推荐

