2

How would I do the following if Rust supported two percent functions?

fn percent(x: u8) -> f32 {
    x as f32 / 100.0
}
fn percent(x: u16) -> f32 {
    x as f32 / 100.0
}

If I try a generic data type like the following:

fn percent<T>(x: T) -> f32 {
    x as f32 / 100.0
}

I get the error

non-primitive cast: T as f32

Can I constrain T with some kind of integer trait?

at.
  • 50,922
  • 104
  • 292
  • 461
  • 2
    Does this answer your question? [Is there any trait that specifies numeric functionality?](https://stackoverflow.com/questions/37296351/is-there-any-trait-that-specifies-numeric-functionality) – N. Shead Mar 13 '20 at 01:58
  • See also https://stackoverflow.com/questions/26810793/how-can-i-create-an-is-prime-function-that-is-generic-over-various-integer-types for a "more advanced" version – hellow Mar 13 '20 at 06:41

1 Answers1

3

If you want to only support u8 and u16 type, then:

fn percent<T: Into<f32>>(x: T) -> f32 {
    x.into() / 100.0
}

is enough, since both u8 and u16 can be losslessly converted into a f32. If you want to generically convert, say a u64 to f64, where a loss of precision can occur, you could use ApproxInto trait from conv.

fn percent<T: ApproxInto<f64>>(x: T) -> Result<f64, T::Err> {
    x.approx_into().map(|v| v / 100.0)
}
charlieh_7
  • 334
  • 3
  • 12
  • This is what I was looking for! Thank you. Is there a slight performance penalty with the `Into` approach? – at. Mar 17 '20 at 23:40
  • 1
    @at. There should not be any since compiler will generate separate copies of code each time you call the function with different types. However sometimes there may be a bug in the compiler. See this article if you want to know more: https://www.joshmcguigan.com/blog/cost-of-indirection-rust/ – charlieh_7 Mar 18 '20 at 06:26