0

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);
}

Rust playground

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?
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Petr Kozelka
  • 7,670
  • 2
  • 29
  • 44
  • [The duplicate applied to your example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=26520d7c78a2eb0fb5217460a7dca14c) – Shepmaster Feb 28 '20 at 18:26
  • @Shepmaster thanks! And, I just noticed that traits can even define kinda "polymorphic" constant, which is much better for defining NAN than was my function call. – Petr Kozelka Feb 28 '20 at 18:48
  • I think you mean an *associated constant*, and yes, that could be a better solution for that case. – Shepmaster Feb 28 '20 at 18:54

0 Answers0