Generics 有没有一种简单的方法可以在Rust中使用完整的泛型类型?

Generics 有没有一种简单的方法可以在Rust中使用完整的泛型类型?,generics,rust,Generics,Rust,我有一系列几乎相同的函数,只是类型和常数不同。例如: fn update16(table: &[u16], init: u16, xs: &[u8]) -> u16 { xs.iter().fold(init, |acc, x| { (acc << 8) ^ table[(((acc >> 8) as u8) ^ x) as usize] }) } fn update32(table: &[u32], init: u32, xs:

我有一系列几乎相同的函数,只是类型和常数不同。例如:

fn update16(table: &[u16], init: u16, xs: &[u8]) -> u16 {
    xs.iter().fold(init, |acc, x| { (acc << 8) ^ table[(((acc >> 8) as u8) ^ x) as usize] })
}

fn update32(table: &[u32], init: u32, xs: &[u8]) -> u32 {
    xs.iter().fold(init, |acc, x| { (acc << 8) ^ table[(((acc >> 24) as u8) ^ x) as usize] })
}
fn update16(表:&[u16],初始化:u16,xs:&[u8])->u16{
iter().fold(init,| acc,x{(acc>8)作为u8)^x)作为usize]})
}
fn update32(表:&[u32],初始化:u32,xs:&[u8])->u32{
iter().fold(init,| acc,x{(acc>24)作为u8)^x)作为usize]})
}
因此,我考虑将此函数作为类型的通用函数:

trait Update<T> {
    fn update(table: &[T], init: T, xs: &[u8]) -> T;
}
trait更新{
fn更新(表:&[T],初始:T,xs:&[u8])->T;
}
我最终实现了这一点:

use std::ops::Shl;
use std::ops::Shr;
use std::ops::BitXor;
use std::mem::size_of;

extern crate num;
use num::ToPrimitive;

struct Normal;

impl<
    T: Copy + Shl<u8, Output = T> + Shr<usize, Output = T> + BitXor<Output = T> + ToPrimitive,
> CrcUpdate<T> for Normal {
    fn update(table: &[T], init: T, xs: &[u8]) -> T {
        xs.iter().fold(init, |acc, x| {
            (acc << 8) ^
                table[(ToPrimitive::to_u8(&(acc >> ((8 * size_of::<T>()) - 8))).unwrap() ^ x) as
                          usize]
        })
    }
}
使用std::ops::Shl;
使用std::ops::Shr;
使用std::ops::BitXor;
使用std::mem::size\u;
外部板条箱数量;
使用num::ToPrimitive;
结构正常;
恳求<
T:Copy+Shl+Shr+BitXor+ToPrimitive,
>正常情况下的CrcUpdate{
fn更新(表:&[T],初始:T,xs:&[u8])->T{
iter()折叠(init,| acc,x |{
(acc>((8*尺寸:())-8))。展开()^x)为
使用]
})
}
}
这比我想象的要复杂得多。我不得不使用一系列特征,定义一个空结构,包括一个外部板条箱,并在某种程度上模糊了基本计算。它肯定比原版多了很多行

在Rust中,这是对整数使用泛型的正确方法吗?还是我错过了一个更简单的方法

是和否

统一处理整数类型不是很顺利。

正如您刚才在这里发现的那样,标准库不提供任何以统一方式处理数字的“统一”特性。目前还不清楚最好的设计是什么,因此像
num
这样的板条箱试图探索设计空间

所以,是的,如果你想用一般的方法处理多重积分,你必须要么拉入外部板条箱(比如
num
),要么忍受一些痛苦

但是,您可以使用更简单的代码。

首先,这样定义一个
结构
特征
是完全没有必要的。Rust具有通用功能:

fn update<T>(table: &[T], init: T, xs: &[u8]) -> T
where
    T: Copy + Shl<u8, Output = T> + Shr<usize, Output = T> + BitXor<Output = T> + ToPrimitive,
{
    xs.iter().fold(init, |acc, x| {
        (acc << 8)
            ^ table[(ToPrimitive::to_u8(&(n >> ((8 * size_of::<T>()) - 8))).unwrap() ^ x) as usize]
    })
}
否则,您可以定义自己的“字节选择”特性。现在它需要更多的线路,但是它有一个更清晰的界面来适应你的领域

trait SelectByte: Sized {
    fn bytes(&self) -> usize { mem::size_of::<Self>() }
    fn lower(&self, n: usize) -> u8;
    fn upper(&self, n: usize) -> u8 { self.lower(self.bytes() - n - 1) }
}

impl SelectByte for u16 {
    fn lower(&self, n: usize) -> u8 {
        assert!(n <= 1);
        ((*self >> (n * 8)) & 255u16) as u8
    }
}

impl SelectByte for u32 {
    fn lower(&self, n: usize) -> u8 {
        assert!(n <= 3);
        ((*self >> (n * 8)) & 255u32) as u8
    }
}
最后,如果您发现自己一遍又一遍地列举同一组约束,请随意为其定义一个新特性:

trait Numeric: Copy + Shl<u8, Output = Self> + BitXor<Output = Self> + SelectByte {}

impl<T> Numeric for T
    where T: Copy + Shl<u8, Output = T> + BitXor<Output = T> + SelectByte
{}
trait Numeric:Copy+Shl+BitXor+SelectByte{}
T的impl数值
其中T:Copy+Shl+BitXor+SelectByte
{}
然后使用快捷方式:

fn update<T: Numeric>(table: &[T], init: T, xs: &[u8]) -> T {
    xs.iter().fold(init, |acc, x| { (acc << 8) ^ table[(acc.upper(0) ^ x) as usize] })
}
fn更新(表:&[T],初始:T,xs:&[u8])->T{

xs.iter().fold(init,| acc,x |{(acc)有没有办法使用num板条箱来避免所有/大部分额外的东西?在我最初的实现中,我还是不得不使用它。@Roxy:我对板条箱不太熟悉,所以……也许吧?你肯定在寻找它。
trait Numeric: Copy + Shl<u8, Output = Self> + BitXor<Output = Self> + SelectByte {}

impl<T> Numeric for T
    where T: Copy + Shl<u8, Output = T> + BitXor<Output = T> + SelectByte
{}
fn update<T: Numeric>(table: &[T], init: T, xs: &[u8]) -> T {
    xs.iter().fold(init, |acc, x| { (acc << 8) ^ table[(acc.upper(0) ^ x) as usize] })
}