Rust如何实现动态Box<dyn Trait<T,S>>存储多泛型参数事务集合
问题原因
你原来的Details<T, S> trait带有泛型参数,Rust中每一组不同的T/S参数对应的Details<T, S>都是完全独立的trait类型,无法作为同一种trait对象存入同一个Vec。
解决方案
拆分trait,把不需要感知T/S具体类型的通用逻辑抽到无泛型的基础trait中,返回动态分发的dyn Debug trait对象替代具体泛型类型即可满足你打印调试的需求。如果后续需要获取具体类型的值,可以让基础trait继承Any实现向下转型。
完整可运行代码如下:
use std::fmt::Debug; use std::any::Any; #[derive(Debug)] struct TransactionSet<T,S> { pub name: String, pub key: T, pub value: S } // 无泛型的基础trait,可作为trait对象统一存储 trait BaseDetails { fn get_details(&self); // 返回dyn Debug即可满足打印需求,不需要知道具体类型 fn get_key(&self) -> &dyn Debug; fn get_value(&self) -> &dyn Debug; // 可选:如果需要后续获取具体类型的值,添加as_any方法支持向下转型 fn as_any(&self) -> &dyn Any; } // 给所有满足T/S实现Debug的TransactionSet实现BaseDetails impl<T: Debug + 'static, S: Debug + 'static> BaseDetails for TransactionSet<T, S> { fn get_details(&self) { println!("{:?} {:?} {:?}", self.name, &self.key, &self.value); } fn get_key(&self) -> &dyn Debug { &self.key } fn get_value(&self) -> &dyn Debug { &self.value } fn as_any(&self) -> &dyn Any { self } } fn print_type_of<T>(_: &T) { println!("{}", std::any::type_name::<T>()) } fn main() { // 现在可以正常声明Vec存储dyn BaseDetails类型的trait对象 let mut vec: Vec<Box<dyn BaseDetails>> = Vec::new(); let a1: TransactionSet<String,String> = TransactionSet { name: String::from("Test1"), key: String::from("name"), value: String::from("vinay") }; let a2: TransactionSet<String,i32> = TransactionSet { name: String::from("Test2"), key: String::from("age"), value: 32_i32 }; let a3 = TransactionSet { name: String::from("Test3"), key: 1_i32, value: 10_u64 }; let a4 = TransactionSet { name: String::from("Test4"), key: String::from("isEligibleToVote"), value: true }; vec.push(Box::new(a1)); vec.push(Box::new(a2)); vec.push(Box::new(a3)); vec.push(Box::new(a4)); for v in vec.iter() { v.get_details(); println!("Key : {:?}", v.get_key()); println!("Value : {:?}", v.get_value()); // 可选:如果你知道某个元素的具体泛型类型,可以向下转型拿具体值 if let Some(ts) = v.as_any().downcast_ref::<TransactionSet<String, i32>>() { println!("匹配到String:i32类型的事务,值为{}", ts.value); } } }
如果你的场景确实需要返回具体的T/S类型而不只是调试打印,那说明你在遍历的时候是知道对应元素的泛型类型的,这种场景下用as_any向下转型即可拿到具体实例调用对应getter。
内容的提问来源于stack exchange,提问作者Vinay Sawant
相关产品推荐
相关产品推荐

