I have some code which converts between f64 and i32, I want to make more generic (type T instead of i32). Most of the methods were easily converted, however I hit a snag here:
non-primitive cast:
f64
asT
note: anas
expression can only be used to convert between primitive types. Consider using theFrom
trait
So I tried to switch from as i32
to i32::from
, but it isn't allowed:
fn main() {
let f: f64 = 0.0;
let a: i32 = f as i32; // works
let b: i32 = i32::from(f); // fails
}
Fails with the error:
the trait
std::convert::From<f64>
is not implemented fori32
Why isn't it implemented? I also cannot implement it myself due to, as I understand it, Rust's orphan rules (which prevent you from implementing external traits for external types). as
does what I want, but I couldn't find any trait to represent a type that can be as
'd.
To make it concrete, here is the code I'm trying to convert:
use std::convert::From;
use std::fmt;
#[derive(Clone, Copy)]
pub struct FixedPoint32(i32);
impl From<f64> for FixedPoint32 {
fn from(x: f64) -> Self {
FixedPoint32((x * 32.0) as i32)
}
}
impl From<FixedPoint32> for f64 {
fn from(x: FixedPoint32) -> Self {
x.0 as f64 / 32.0
}
}
impl fmt::Debug for FixedPoint32 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FixedPoint32({} = {})", self.0, f64::from(*self))
}
}
fn main() {
let f = FixedPoint32::from(1.0);
println!("f = {:?}", f);
}
Here's my broken attempt at making the code generic. It almost works, the first two methods compile but I can't seem to use it due to the missing From<f64>
trait implementation on i32
, nor implement the fmt
method:
use std::convert::From;
use std::fmt;
#[derive(Clone, Copy)]
pub struct FixedPoint<T>(T);
impl<T: From<f64>> From<f64> for FixedPoint<T> {
fn from(x: f64) -> Self {
FixedPoint::<T>(T::from(x * 32.0))
}
}
impl<T: From<f64>> From<FixedPoint<T>> for f64 where f64: From<T> {
fn from(x: FixedPoint<T>) -> Self {
f64::from(x.0) / 32.0
}
}
impl<T> fmt::Debug for FixedPoint<T> where T: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//write!(f, "FixedPoint32({} = {})", self.0, f64::from(*self))
Ok(())
}
}
fn main() {
let f: FixedPoint<i32> = 1.0.into();
println!("f = {:?}", f);
}
fails with the same error:
error[E0277]: the trait bound `i32: std::convert::From<f64>` is not satisfied
--> /private/tmp/foo2.rs:27:34
|
27 | let f: FixedPoint<i32> = 1.0.into();
| ^^^^ the trait `std::convert::From<f64>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as std::convert::From<bool>>
<i32 as std::convert::From<i16>>
<i32 as std::convert::From<i8>>
<i32 as std::convert::From<std::num::NonZeroI32>>
and 2 others
= note: required because of the requirements on the impl of `std::convert::From<f64>` for `FixedPoint<i32>`
= note: required because of the requirements on the impl of `std::convert::Into<FixedPoint<i32>>` for `f64`
Am I missing something, is there a workaround for From not allowing f64 to i32 conversion, or a better way to accomplish what I'm trying to do here?