假设我有一个函数将一个数字参数与一个常量进行比较并返回一个布尔值:
fn compare(n: f64) -> bool {
n > 42 as f64
}
这工作正常,但我似乎无法使其通用:
fn compare<T: Ord>(n: T) -> bool {
n > 42 as T // error: non-scalar cast: `<VI0>` as `T`
}
fn compare<T: Ord>(n: T) -> bool {
n > 42 // mismatched types: expected `T` but found `<VI0>` (expected type parameter but found integral variable)
}
fn compare<T: Num>(n: T) -> bool {
n > 42 // error: binary operation > cannot be applied to type `T`
}
你会怎么做到这一点?
正如你所见,Rust as
操作员在它允许的演员表中非常有限。根据 铁锈手册,
可以将数值转换为任何数字类型。原始指针值可以转换为任何整数类型或原始指针类型。任何其他强制转换都不受支持,无法编译。
此外,Rust不执行任何类型的隐式运行时数字强制,因此您必须将比较运算符的参数明确强制转换为相同类型(因为 Ord
定义一个 lt
原型的方法 fn lt(&self, other: &Self)
)。
这引出了一个有趣的观点 - 论者的论据应该是哪种类型 <
你的经营者 compare
功能被投射, T
要么 int
(假定的类型 42
)?在这种情况下,您似乎想要进行比较 n
价值 42
转换成后 T
。在保持通用性的同时实现这一目标的最直接的方法是要求 T
实施 FromPrimitive
特质,包含在外部 num
箱,它提供了获取类型值的方法 T
从一个 int
(或其他Rust原始数字类型)。你的 compare
函数可以这样写:
extern crate num;
use num::FromPrimitive;
fn compare<T: Ord + FromPrimitive>(n: T) -> bool {
n > FromPrimitive::from_int(42).expect("42 must be convertible to type of n")
}
为了测试这个,我创建了一个简单的 BinaryNumber
表示二进制数的类型,作为数组 bool
:
use std::num::abs;
type Bits = [bool, ..64];
struct BinaryNumber {
priv negbit: bool,
priv bits: Bits,
}
fn bits_from_u64(n: u64) -> Bits {
let mut bits = [false, ..64];
for i in range(0u, 64u) {
if ((1 << i) & n) != 0 {
bits[i] = true;
}
}
bits
}
impl FromPrimitive for BinaryNumber {
fn from_u64(n: u64) -> Option<BinaryNumber> {
Some(BinaryNumber {
negbit: false,
bits: bits_from_u64(n.to_u64().unwrap())
})
}
fn from_i64(n: i64) -> Option<BinaryNumber> {
Some(BinaryNumber {
negbit: n < 0,
bits: bits_from_u64(abs(n).to_u64().unwrap())
})
}
}
impl Eq for BinaryNumber {
fn eq(&self, other: &BinaryNumber) -> bool {
if self.negbit != other.negbit { return false }
for i in range(0, 64).map(|i| 64 - 1 - i) {
if self.bits[i] != other.bits[i] {
return false;
}
}
true
}
}
impl Ord for BinaryNumber {
fn lt(&self, other: &BinaryNumber) -> bool {
match (self.negbit, other.negbit) {
(true, false) => true,
(false, true) => false,
_ => {
let neg = self.negbit;
for i in range(0, 64).map(|i| 64 - 1 - i) {
if neg && self.bits[i] && !other.bits[i] {
return true;
} else if !self.bits[i] && other.bits[i] {
return true;
}
}
false
}
}
}
}
然后是代码
fn main() {
let x: BinaryNumber = FromPrimitive::from_int(0).unwrap();
let y: BinaryNumber = FromPrimitive::from_int(42).unwrap();
let z: BinaryNumber = FromPrimitive::from_int(100).unwrap();
println!("compare(x) = {}", compare(x));
println!("compare(y) = {}", compare(y));
println!("compare(z) = {}", compare(z));
}
版画
compare(x) = false
compare(y) = false
compare(z) = true
你可以试试这个
compare<T: PartialOrd<i32>>(n: T) -> bool {
n > 42
}
表达 lhs> rhs 等于 <T as PartialOrd <U >> :: gt(&lhs,&rhs)
哪里 LHS 有类型 Ť 和 RHS 有类型 ü
从而 Ť 必须实施 PartialOrd 为了允许使用操作员 >