I am trying to implement a couple of simple computations that will be frequently used throughout my project, and want to reuse code in the best available way for all applicable numerical types.
However, I seem to be hitting limits of my understanding of Rust generics.
use std::ops::{Div, Sub};
pub trait HasNan: PartialEq {
fn nan() -> Self;
}
impl HasNan for f64 {
fn nan() -> Self {
std::f64::NAN
}
}
impl HasNan for f32 {
fn nan() -> Self {
std::f32::NAN
}
}
pub trait MyScaleOperation: Sized + PartialEq + HasNan + Sub<Self> + Div<Self> {
fn scale_op(self, mean: Self, scale: Self) -> Self {
if self != self {
Self::nan()
} else {
(self - mean) / scale
}
}
}
impl MyScaleOperation for f32 {}
impl MyScaleOperation for f64 {}
fn main() {
// f32
let x1: f32 = 25.0;
let y1 = x1.scale_op(5.0, 4.0);
println!("f32 scale: {} -> {}", x1, y1);
// f64
let x1: f32 = 75.0;
let y1 = x1.scale_op(5.0, 7.0);
println!("f32 scale: {} -> {}", x1, y1);
}
error[E0369]: binary operation `/` cannot be applied to type `<Self as std::ops::Sub>::Output`
--> src/main.rs:24:27
|
24 | (self - mean) / scale
| ------------- ^ ----- Self
| |
| <Self as std::ops::Sub>::Output
|
= note: an implementation of `std::ops::Div` might be missing for `<Self as std::ops::Sub>::Output`
Questions:
- is this kind of code reuse really possible?
- how?
- is that even a good idea to try, or is there a better, more idiomatic approach?