I want to check return codes of C APIs in a generic way and the result must be free from C types such as libc::c_int
. Are there any ways to write a function like
fn check<S: PartialOrd + std::num::Zero, T> (x: S) -> Option<T> {
if std::num::zero::<S>() <= x { Some(x as T) }
else { None }
}
when I'm sure that S
and T
are integral types for all usages of check()
? The compiler rejects my code complaining error: non-scalar cast: `S` as `T`
It is impossible to cast arbitrary type to arbitrary type, and that's exactly (almost) what you're trying to do. You need to be more specific in type constraints and conversion operations.
extern crate num;
use num::{Zero, NumCast};
fn check<S: PartialOrd + Zero + NumCast, T: NumCast>(x: S) -> Option<T> {
if x >= S::zero() { Some(num::cast(x).unwrap()) }
else { None }
}
fn main() {
let x: i8 = 10;
let y: Option<i32> = check(x);
println!("{:?}", y);
let x: i8 = -10;
let y: Option<i32> = check(x);
println!("{:?}", y);
}
Here I'm using a special trait, num::NumCast
from num
crate, which is implemented for all primitive types and provides a static method which converts to these types from anything which implements num::ToPrimitive
. num
crate also provides a function, num::cast::cast()
, which gives a simple interface to perform numeric casts.
Note that cast(x)
returns Option<T>
; it returns None
if x
can't be represented in the target type. I'm using unwrap()
here because in your case, according to your description, inability to convert a value correctly is likely a programming error, so failing the task feels more appropriate. It is also possible to write cast(x)
directly:
if x >= S::zero() { num::cast(x) }
...
In this case check()
will return None
not only when its argument is negative, but also if it is impossible to convert the argument to the result type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With