如何为不同结构体向量通过Trait实现复用的verify函数?
问题
我有三个向量类型:
Vec<RawTransaction> Vec<RawCashTransaction> Vec<RawAdjustmentTransaction>
它们都实现了VerifyableRaw trait及其verify()方法,用于检查向量内容的有效性。这三个结构体都包含共同的基础字段:date、total、credit和debit。
目前的问题是:由于verify()方法需要访问这些共同字段,我只能在每个向量类型的Trait实现中复制粘贴完全相同的代码。我想知道是否可以将这个Trait实现重构为单一函数定义,避免后续新增结构体时重复编写代码。
结构体定义
pub struct RawTransaction { pub date: Option<NaiveDate>, pub contact_name: String, pub total: Option<Decimal>, pub credit: String, pub debit: String, } pub struct RawCashTransaction{ pub tr_type: String, pub date: Option<NaiveDate>, pub contact_name: String, pub total: Option<Decimal>, pub credit: String, pub debit: String, } pub struct RawAdjustmentTransaction{ pub date: Option<NaiveDate>, pub info: String, pub total: Option<Decimal>, pub credit: String, pub debit: String, }
现有Trait实现
#[async_trait] pub trait VerifyableRaw { async fn verify(&self, cid: String, db: Database) -> Result<bool, Err>; } #[async_trait] impl VerifyableRaw for Vec<RawTransaction> { async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> { /// .... 这段逻辑三个实现完全一致 let data = &self; // 访问向量 for (i, row) in data.iter().enumerate() { // 遍历向量中的每个元素 let date = row.date.unwrap(); // 检查日期有效性等 let de = row.debit.clone(); // 检查该值有效性 let cr = row.credit.clone(); // 检查该值有效性 // ... 其他处理逻辑 ... } } } #[async_trait] impl VerifyableRaw for Vec<RawCashTransaction> { async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> { /// .... 这段逻辑和上面完全相同 } } #[async_trait] impl VerifyableRaw for Vec<RawAdjustmentTransaction> { async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> { /// .... 这段逻辑和上面完全相同 } }
解决方案
可以通过提取共同字段到新Trait的方式实现代码复用,具体步骤如下:
1. 定义包含共同字段访问方法的Trait
创建一个Trait抽象三个结构体的共同字段,提供统一的访问接口:
pub trait RawTransactionCommon { fn date(&self) -> &Option<NaiveDate>; fn total(&self) -> &Option<Decimal>; fn credit(&self) -> &String; fn debit(&self) -> &String; }
2. 为每个结构体实现该Trait
让三个结构体分别实现RawTransactionCommon,统一共同字段的访问逻辑:
impl RawTransactionCommon for RawTransaction { fn date(&self) -> &Option<NaiveDate> { &self.date } fn total(&self) -> &Option<Decimal> { &self.total } fn credit(&self) -> &String { &self.credit } fn debit(&self) -> &String { &self.debit } } impl RawTransactionCommon for RawCashTransaction { fn date(&self) -> &Option<NaiveDate> { &self.date } fn total(&self) -> &Option<Decimal> { &self.total } fn credit(&self) -> &String { &self.credit } fn debit(&self) -> &String { &self.debit } } impl RawTransactionCommon for RawAdjustmentTransaction { fn date(&self) -> &Option<NaiveDate> { &self.date } fn total(&self) -> &Option<Decimal> { &self.total } fn credit(&self) -> &String { &self.credit } fn debit(&self) -> &String { &self.debit } }
3. 为所有Vec<T>(T实现RawTransactionCommon)实现VerifyableRaw
利用Rust的泛型Trait实现,只需写一次verify逻辑,自动适配所有符合条件的向量类型:
#[async_trait] impl<T: RawTransactionCommon + Sync> VerifyableRaw for Vec<T> { async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> { // 核心验证逻辑只需编写一次 for (i, row) in self.iter().enumerate() { let date = row.date().unwrap(); // 通过Trait方法访问字段 let de = row.debit().clone(); let cr = row.credit().clone(); // ... 其他原有验证逻辑 ... } Ok(true) // 根据实际业务逻辑返回结果 } }
关键说明
- 添加
Sync约束是因为async_trait要求异步方法的参数满足线程安全,若你的场景无需跨线程,可根据实际情况调整。 - 后续新增类似结构体时,只需实现
RawTransactionCommontrait,对应的Vec<NewStruct>会自动拥有verify方法,无需重复编写验证逻辑。
内容的提问来源于stack exchange,提问作者DennyHiu
相关产品推荐
相关产品推荐

