我有3个Vec<T>
结构体共享相同的函数:
Vec<RawTransaction>
Vec<RawCashTransaction>
Vec<RawAdjustmentTransaction>
这三个函数都有相同的VerifyableRaw
特性和verify()
函数,我使用verify()
函数检查数组/向量内容的有效性。
下面是我的实现。正如您所看到的,它们都共享相同的基本字段,即:date
、total
、credit
和debit
中的一个或多个。
我的问题是:因为我使用了这些结构体共享的相同字段,所以verify()
函数对所有这些结构体都是相同的。在verify
函数中,我需要访问date
、total
、credit
和debit
字段,所以我只是将代码从一个实现复制并粘贴到另一个实现中。
我的问题是:我可以将这个trait实现重构为一个函数定义吗?
我发现每次需要对另一个结构体使用verify()
函数和VerifyableRaw
特征时,我都需要重复自己的操作
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,
}
下面是我的特征实现:
#[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> {
/// .... this function is the same for all three
let data = &self; // access the vector
for (i, row) in data.iter().enumerate() {
// enumerate each item in this vector
let date = row.date.unwrap(); // check if the date is valid, etc
let de = row.debit.clone(); // check if this value is valid
let cr = row.credit.clone(); // check if this value is valid
// ... another process here ...
}
}
}
#[async_trait]
impl VerifyableRaw for Vec<RawCashTransaction> {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> {
/// .... this function is exactly the same as RawTransaction above
}
}
#[async_trait]
impl VerifyableRaw for Vec<RawAdjustmentTransaction> {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> {
/// .... this function is exactly the same as RawTransaction above
}
}
2条答案
按热度按时间unftdfkk1#
为了避免重复,可以将公共字段放在一个结构体中,而不是将每个字段都复制到每个具体结构体中,只需包含一个类型为公共类型的字段:
则
impl AsRef<BaseTransaction>
为每种混凝土类型:现在你可以有一个通用函数来操作
AsRef<BaseTransaction>
:ccgok5k52#
是的,您可以:
您仍然必须为每个类型的访问方法编写实现,但我相信这比复制复杂的业务逻辑要好。
如果你有太多这样的类型,而你又不想为每一个类型手工编写getter,那么编写一个宏来为你做这件事是很简单的。但是对于仅仅3个类型,我不推荐这样做,因为宏会使事情变得比它们需要的复杂得多。