7

I have a generic struct with one field, that can only be i32 or f32.

trait MyInt {
    fn blank();
}

impl MyInt for i32 {
    fn blank() {
        unimplemented!()
    }
}

impl MyInt for f32 {
    fn blank() {
        unimplemented!()
    }
}

struct MyStruct<T> where T: MyInt {
    field: T
}

impl<T> MyStruct<T> where T: MyInt {
    fn new(var: T) -> MyStruct<T> {
        MyStruct {
            field: var
        }
    }
}

Now I want to add a method which returns field value as f32, whether it's i32 or f32. I know that this cast should always be possible since field types are limited to two mentioned above, but how do I go about it? Apparently as only works on primitive types and I tried going the From route, but I am doing something wrong, this doesn't work.

fn to_f32(&self) -> f32 where T: From<i32> {
        f32::from(self.field);
}
estw272
  • 211
  • 5
  • 20
  • 2
    You do realize that a number of `i32` values cannot be represented (exactly) as a `f32` because by IEEE standard `f32` only has a 23 bits mantissa (so it could represent an hypothetical `i24` but no more). – Matthieu M. Mar 03 '16 at 08:11

2 Answers2

4

You can simply add the cast as a method to your MyInt trait:

trait MyInt {
    fn to_f32_lossy(self) -> f32;
}

impl MyInt for i32 {
    fn to_f32_lossy(self) -> f32 {
        self as f32
    }
}

impl MyInt for f32 {
    fn to_f32_lossy(self) -> f32 {
        self
    }
}
oli_obk
  • 28,729
  • 6
  • 82
  • 98
4

You are right, as only works with concrete types.

Using the From or Into trait for the conversion is a good approach, but these are not implemented for a i32 -> f32 conversion. The reason is most likely that it's a potentially lossy conversion as Matthieu M. says.

You'll have to work with f64 instead of f32.

I would suggest changing the trait to this:

trait MyInt: Copy + Into<f64> {
    fn blank();
}

Then you can add the method to do the conversion:

fn to_f64(&self) -> f64 {
    self.field.into()
}
A.B.
  • 15,364
  • 3
  • 61
  • 64
  • 1
    Thanks for you reply. Can you explain what this line `trait MyInt: Copy + Into` means? Types implementing `MyInt` trait also should have `Copy` and `Into` traits implemented? – estw272 Mar 03 '16 at 10:16
  • 2
    @ehsisthatsweird: yes, the portion after the `:` spells out the requirement that a type has to fulfill for `MyInt` to be implementable; it also means that when using a type that implements `MyInt` you know it necessarily implements those other traits. – Matthieu M. Mar 03 '16 at 10:46