9

Regular float literals do not work:

extern crate num_traits;

use num_traits::float::Float;

fn scale_float<T: Float>(x: T) -> T {
    x * 0.54
}

fn main() {
    let a: f64 = scale_float(1.23);
}
error[E0308]: mismatched types
 --> src/main.rs:6:9
  |
6 |     x * 0.54
  |         ^^^^ expected type parameter, found floating-point variable
  |
  = note: expected type `T`
             found type `{float}`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
goertzenator
  • 1,960
  • 18
  • 28

4 Answers4

14

Use the FromPrimitive trait:

use num_traits::{cast::FromPrimitive, float::Float};

fn scale_float<T: Float + FromPrimitive>(x: T) -> T {
    x * T::from_f64(0.54).unwrap()
}

Or the standard library From / Into traits

fn scale_float<T>(x: T) -> T
where
    T: Float,
    f64: Into<T>
{
    x * 0.54.into()
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thanks. First one works, second one doesn't due to lack of f64->f32 conversion. Fixed on [playground](https://play.rust-lang.org/?gist=35c7f1b82aac65be5119001fc586e181&version=stable&mode=debug). Inspection of assembly shows this is zero cost so I'm happy! – goertzenator Jun 09 '18 at 14:06
  • @goertzenator you could go the other way (`f32: Into`). – Shepmaster Jun 09 '18 at 14:19
2

In certain cases, you can add a restriction that the generic type must be able to be multiplied by the type of the literal. Here, we allow any type that can be multiplied by a f64 so long as it produces the output type of T via the trait bound Mul<f64, Output = T>:

use num_traits::float::Float; // 0.2.6
use std::ops::Mul;

fn scale_float<T>(x: T) -> T
where
    T: Float + Mul<f64, Output = T>,
{
    x * 0.54
}

fn main() {
    let a: f64 = scale_float(1.23);
}

This may not work directly for the original problem, but it might depending on what concrete types you need to work with.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
1

You can't create a Float from a literal directly. I suggest an approach similar to the FloatConst trait:

trait SomeDomainSpecificScaleFactor {
    fn factor() -> Self;
}

impl SomeDomainSpecificScaleFactor for f32 {
    fn factor() -> Self {
        0.54
    }
}

impl SomeDomainSpecificScaleFactor for f64 {
    fn factor() -> Self {
        0.54
    }
}

fn scale_float<T: Float + SomeDomainSpecificScaleFactor>(x: T) -> T {
    x * T::factor()
}

(link to playground)

mcarton
  • 27,633
  • 5
  • 85
  • 95
1

These days the numeric_literals crate and its replace_float_literals feature can be helpful in doing the necessary substitutions on a complex piece of code.

PO8
  • 73
  • 1
  • 9