9

我想以通用方式检查 C API 的返回码,结果必须不含 C 类型,例如libc::c_int. 有没有办法写一个像

fn check<S: PartialOrd + std::num::Zero, T> (x: S) -> Option<T> {
    if std::num::zero::<S>() <= x { Some(x as T) }
    else { None }
}

当我确定S并且T是所有用法的整数类型时check()?编译器拒绝我的代码抱怨error: non-scalar cast: `S` as `T`

4

1 回答 1

14

将任意类型转换为任意类型是不可能的,而这正是(几乎)您想要做的。您需要在类型约束和转换操作方面更加具体。

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);
}

在这里,我使用了一个特殊的 trait,num::NumCast来自numcrate,它为所有原始类型实现,并提供了一个静态方法,该方法可以从任何实现num::ToPrimitive. numcrate 还提供了一个函数 ,num::cast::cast()它提供了一个简单的接口来执行数字转换。

请注意,cast(x)返回Option<T>; None如果x无法在目标类型中表示,则返回。我在unwrap()这里使用是因为在您的情况下,根据您的描述,无法正确转换值可能是编程错误,因此任务失败感觉更合适。也可以cast(x)直接写:

if x >= S::zero() { num::cast(x) }
...

在这种情况下,不仅check()会在其参数为负数时返回None,而且在无法将参数转换为结果类型时也会返回。

于 2014-09-25T17:31:21.123 回答