PartialOrd for integer generic types

I have some code as below:

fn compare<T: std::cmp::PartialOrd<i32>>(v: T) ->bool {
    v > 10
}

fn main() {
    let i : i32 = 9;
    println!("{}", compare(i));
    let j : u32 = 9;
    println!("{}", compare(j));
}

want I want is to campare the v with 10, as long as the V is an number, but the code does not work as I expect:

error[E0277]: can't compare `u32` with `i32`
  --> src/main.rs:15:28
   |
7  | fn compare<T: std::cmp::PartialOrd<i32>>(v: T) ->bool {
   |               ------------------------- required by this bound in `compare`
...
15 |     println!("{}", compare(j));
   |                            ^ no implementation for `u32 < i32` and `u32 > i32`
   |
   = help: the trait `PartialOrd<i32>` is not implemented for `u32`

Then I tried this:

fn compare<T: std::cmp::PartialOrd<T>>(v: T) ->bool {
    v > 10 as T
}

but than the compiler said:

error[E0605]: non-primitive cast: `i32` as `T`
 --> src/main.rs:8:9
  |
8 |     v > 10 as T
  |         ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object

so how can I promise that all the T in the program is an primitive type? I didn't find any trait to do this.

You can use FromPrimitive to convert 10 to T:

use num_traits::FromPrimitive;

fn compare<T: PartialOrd + FromPrimitive>(v: T) -> bool {
    let ten = T::from_i8(10).expect("unrepresentable");
    v > ten
}

Please note that the conversion can fail. Obviously it won't fail if you convert 10 to u32, but for example, it will fail if you try to convert 257 to u8, so you need to account for that. The example above panics in this case.

This is some how not what I want, since 10 can be represent by u8, the converting will always success... What I want is to make type constrain on compile time, and except seems have performance issues. Any ways to do that? Or, will except in this case has extra overload?

If the optimizer can see that something always succeeds, then it will remove all error handling code.

1 Like

you could do this also:

fn compare<T: std::cmp::PartialOrd>(v: T, num: T) -> bool {
    v > num
}

You can't guarantee FromPrimitive will always succeed because your function is generic, and some exotic types may not be able to convert from 10 (e.g. a type with allowed range defined by const generics).

If you really need the guarantee and you only care about 10, you could create your own trait, for example:

trait WithTen {
    const TEN: Self;
}
impl WithTen for u32 {
    const TEN: Self = 10;
}

The exact shape of the trait would depend on the actual task you're solving, of course.

As for performance concerns, the compiler will probably inline the constant anyway. You can use godbolt to check that.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.