问题
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`
回答1:
Updated for Rust 1.x
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.
来源:https://stackoverflow.com/questions/26042703/how-to-cast-generic-types-that-i-know-to-be-integers