将通用数字参数与常量进行比较 [英] Compare a generic number argument with a constant

查看:107
本文介绍了将通用数字参数与常量进行比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个函数将一个数字参数与一个常量进行比较,并返回一个布尔值:

  fn compare(n: f64) - > bool {
n> 42作为f64
}

这工作正常,但我似乎无法做到generic:

  fn比较< T:Ord>(n:T) - > bool {
n> 42作为T //错误:非标量演员:`< VI0>作为'T`
}

fn比较< T:Ord>(n:T) - > bool {
n> 42 //错配类型:预期的'T'但是找到'< VI0>'(预期的类型参数,但找到整数变量)
}

fn比较< T:Num>(n: T) - > bool {
n> 42 //错误:二进制操作>不能应用于'T`
}

你会如何完成这项工作? p>

解决方案

正如您所看到的,Rust 作为运算符在它允许的演员阵容。根据防锈手册


数值可以转换为任何数值类型。原始指针值可以转换为任何整型或原始指针类型。任何其他的转换都不被支持,并且无法编译。


此外,Rust不会执行任何隐式的运行时数字强制,所以你必须显式强制比较运算符的参数为相同类型(因为 Ord 定义了一个 lt 方法与原型 fn lt(&self; other:& self))。



有意思的是 - 你的比较函数中的< 运算符的参数应该投射到哪种类型, T int (推定的 42 类型)?在这种情况下,您想在转换为后将 n 42 Ť。在保持通用性的同时,最直接的方法是要求 T 实现 FromPrimitive 特征。 io / crates / numrel =nofollow> num crate ,它提供获取类型 T int (或其他Rust原始数值类型)。你的 compare 函数可以这样写:

  extern crate num ; 

使用num :: FromPrimitive;

fn比较< T:Ord + FromPrimitive>(n:T) - > bool {
n> FromPrimitive :: from_int(42).expect(42必须转换为n的类型)
}

为了测试这个,我创建了一个简单的 BinaryNumber 类型,它代表一个二进制数作为 bool 的数组:

 使用std :: NUM :: ABS; 

类型Bits = [bool,..64];

struct BinaryNumber {
priv negbit:bool,
priv bits:Bits,
}

fn bits_from_u64(n:u64) - >位{
让mut位= [false,..64]; (0u,64u){
if((1 << i)& n)!= 0 {
bits [i] = true;




$ b $ impl FromPrimitive for BinaryNumber {
fn from_u64(n:u64) - >选项< BinaryNumber> {
Some(BinaryNumber {
negbit:false,
bits:bits_from_u64(n.to_u64()。unwrap())
})
}
fn from_i64(n:i64) - >选项< 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 {
如果self.negbit!= other.negbit {return false}
在范围内(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)=>假,
_ => {
let neg = self.negbit;
在范围内(0,64).map(| i | 64 - 1 - i){
如果neg&& self.bits [i]&& !other.bits [i] {
return true;
} else if!self.bits [i]&& other.bits [i] {
return true;
}
}
false
}
}
}
}

然后下面的代码

  fn main(){
让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));

$ / code>

打印

 compare(x)= false 
compare(y)= false
compare(z)= true


Suppose I have a function that compares a number argument to a constant and returns a boolean:

fn compare(n: f64) -> bool {
  n > 42 as f64
}

This works fine, but I can't seem to make it generic:

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`
}

How would you accomplish this?

解决方案

As you've seen, the Rust as operator is very limited in the casts it allows. According to the Rust manual,

A numeric value can be cast to any numeric type. A raw pointer value can be cast to or from any integral type or raw pointer type. Any other cast is unsupported and will fail to compile.

Furthermore, Rust doesn't do any sort of implicit run-time numeric coercion, so you have to explicitly coerce the arguments of the comparison operators to the same type (since Ord defines an lt method with the prototype fn lt(&self, other: &Self)).

This brings up an interesting point -- to which type should the arguments to the < operator in your compare function be cast, T or int (the presumed type of 42)? It seems in this case that you want to compare n to the value 42 after conversion to T. The most straightforward way to accomplish this while remaining generic is to require that T implement the FromPrimitive trait, contained in the external num crate, which provides methods from obtaining a value of type T from an int (or other Rust primitive numeric types). Your compare function can then be written like this:

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


To test this out, I created a simple BinaryNumber type that represents a binary number as an array of 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
            }
        }
    }
}

Then then following code

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

prints

compare(x) = false
compare(y) = false
compare(z) = true

这篇关于将通用数字参数与常量进行比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆