I'd like to define several similar types struct A(Option), struct B(Option) etc., where a floating point value is constrained within a range. The structs may differ further a little bit in their behaviour, but the constructor of each type ist the same: it returns Some(value) if the value is already constrained, otherwise None. To avoid having to implement each constructor individually for each type; I'd like to implement it in the trait. Is this really not possible?
Using the following below, I am told that Self is not a function and that I
can't use
Self
as a constructor, you must use the implemented struct
.
#[derive(Debug)]
struct A(Option<f64>);
trait Constrained {
const MIN: f64;
const MAX: f64;
fn is_constrained(value: f64) -> bool {
value >= Self::MIN && value <= Self::MAX
}
fn new(value: f64) -> Self where Self: std::marker::Sized {
if Self::is_constrained(value) {
Self(Some(value))
} else {
Self(None)
}
}
}
impl Constrained for A {
const MIN: f64 = -360.0;
const MAX: f64 = 360.0;
/*
fn new(value: f64) -> A {
if Self::is_constrained(value) {
Self(Some(value))
} else {
Self(None)
}
}
*/
}
fn main() {
let some_val: A = A::new(1000.0);
println!("{:?}", some_val);
}
Commenting out the implementation of the new function in the trait (starting before where), and uncommenting the impl for each indivdiual struct works of course, but this leads to unncessary code doubling for each type. Is there anything possible or planned to generalize this?
Constrained
as a struct generic over a (possibly zero-sized) type that implements aConstraint
trait. The struct governs your data layout and the trait governs behavior. Here's one way to do it, but I can think of several variations. – trentcl