I'm just starting in the Rust (come from python and C#) world and I know this question has been asked many times, but I'm struggling to understand the answers as they are very generic (Foo, Bar, Baz). I'm not even sure if what I need is achievable in Rust.
I need a class to inherit a method from its parent and grand-parent as well and force it to implement functions defined in its parent.
Case:
As you can see in the Code section bellow, Days30BondCounter
and Days30ECounter
structs
return the day_count
with the same expresion. All the difference is in how d1
and d2
is calculated.
My Idea is to create a Days30 abstract class that inherits from DayCounter
but that requires implementing get_d1
and get_d2
functions. So that Days30 looks something like
trait Days30 : DayCounter {
fn get_d1(&self, start_date: NaiveDate, end_date: NaiveDate) -> i32;
fn get_d2(&self, start_date: NaiveDate, end_date: NaiveDate) -> i32;
fn day_count(&self, start_date: NaiveDate, end_date: NaiveDate) -> i64 {
let d1 = self.get_d1(start_date, end_date);
let d2 = self.get_d2(start_date, end_date);
(360 * (end_date.year() - start_date.year()) + 30 * ((end_date.month() - start_date.month()) as i32) + d2 - d1) as i64
}
}
struct Days30BondCounter;
impl Days30 for Days30BondCounter { // this fails
fn get_d1(&self, start_date: NaiveDate, end_date: NaiveDate) -> i32 {
1 // d1 logic
}
fn get_d2(&self, start_date: NaiveDate, end_date: NaiveDate) -> i32 {
2 // d2 logic
}
}
Code:
use chrono::{Datelike, NaiveDate, TimeDelta};
use std::cmp::min;
trait DayCounter { // Base Class
fn day_count(&self, start_date: NaiveDate, end_date: NaiveDate) -> i64;
fn day_count_vector(&self, start_date: NaiveDate, end_dates: &Vec<NaiveDate>) -> Vec<i64> {
let mut result: Vec<i64> = Vec::with_capacity(end_dates.len()); // Replace with VLA
for end_date in end_dates {
result.push(self.day_count(start_date, *end_date));
}
result
}
}
struct ActualCounter; // Simple child
impl DayCounter for ActualCounter {
fn day_count(&self, start_date: NaiveDate, end_date: NaiveDate) -> i64 {
let duration: TimeDelta = end_date.signed_duration_since(start_date);
duration.num_days()
}
}
struct Days30BondCounter; // This is currently a Child. I'd like it to inherit from Days30 which inherits from DayCounter
impl DayCounter for Days30BondCounter {
fn day_count(&self, start_date: NaiveDate, end_date: NaiveDate) -> i64 {
let mut d1: i32 = start_date.day() as i32;
d1 = min(d1, 30);
let mut d2: i32 = end_date.day() as i32;
if d1 > 29 {
d2 = min(d2, 30);
}
(360 * (end_date.year() - start_date.year()) + 30 * ((end_date.month() - start_date.month()) as i32) + d2 - d1) as i64
}
}
struct Days30ECounter; // This is currently a Child. I'd like it to inherit from Days30 which inherits from DayCounter
impl DayCounter for Days30ECounter {
fn day_count(&self, start_date: NaiveDate, end_date: NaiveDate) -> i64 {
let d1: i32 = min(start_date.day(), 30) as i32;
let d2: i32 = min(end_date.day(), 30) as i32;
(360 * (end_date.year() - start_date.year()) + 30 * ((end_date.month() - start_date.month()) as i32) + d2 - d1) as i64
}
}
Extra Info:
DayCounter
is like the base class. Any implementation must define a way to count days between 2 dates inday_count
method.get_d1
andget_d2
areDays30
only methods (non useful inActualCounter
implementation). Its results gived1
andd2
to be used inDays30
implementation ofday_count
abstract class
that inherits from DayCounter but that requires implementing get_d1 and get_d2 functions" - but Rust doesn't have classes, nor "inheritance" - you need to change your way of thinking, instead of trying to code C#/Java in Rust.day_count
instead of just implementing get_d1 and get_d2.day_count
onDays30
, which is unrelated today_count
onDayCounter
try implementing it. Generically, i.e.impl<T: Days30> DayCounter for T {...}
.