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

如何为不同结构体向量通过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要求异步方法的参数满足线程安全,若你的场景无需跨线程,可根据实际情况调整。
  • 后续新增类似结构体时,只需实现RawTransactionCommon trait,对应的Vec<NewStruct>会自动拥有verify方法,无需重复编写验证逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:45:30