当前位置: 首页 > news >正文

【typenum】 17 非负数标记

一、源码

这段代码是 Rust 中用于实现编译时无符号整数的核心部分。它定义了一个 Unsigned trait 并为两种类型实现了该 trait:UTerm(表示零)和 UInt<U, B>(表示非零数字)。

  1. 定义(marker_traits.rs)
/// The **marker trait** for compile time unsigned integers.
///
/// # Example
/// ```rust
/// use typenum::{Unsigned, U3};
///
/// assert_eq!(U3::to_u32(), 3);
/// assert_eq!(U3::I32, 3);
/// ```
pub trait Unsigned: Sealed + Copy + Default + 'static {#[allow(missing_docs)]const U8: u8;#[allow(missing_docs)]const U16: u16;#[allow(missing_docs)]const U32: u32;#[allow(missing_docs)]const U64: u64;#[cfg(feature = "i128")]#[allow(missing_docs)]const U128: u128;#[allow(missing_docs)]const USIZE: usize;#[allow(missing_docs)]const I8: i8;#[allow(missing_docs)]const I16: i16;#[allow(missing_docs)]const I32: i32;#[allow(missing_docs)]const I64: i64;#[cfg(feature = "i128")]#[allow(missing_docs)]const I128: i128;#[allow(missing_docs)]const ISIZE: isize;#[allow(missing_docs)]fn to_u8() -> u8;#[allow(missing_docs)]fn to_u16() -> u16;#[allow(missing_docs)]fn to_u32() -> u32;#[allow(missing_docs)]fn to_u64() -> u64;#[cfg(feature = "i128")]#[allow(missing_docs)]fn to_u128() -> u128;#[allow(missing_docs)]fn to_usize() -> usize;#[allow(missing_docs)]fn to_i8() -> i8;#[allow(missing_docs)]fn to_i16() -> i16;#[allow(missing_docs)]fn to_i32() -> i32;#[allow(missing_docs)]fn to_i64() -> i64;#[cfg(feature = "i128")]#[allow(missing_docs)]fn to_i128() -> i128;#[allow(missing_docs)]fn to_isize() -> isize;
}
  1. 实现
impl Unsigned for UTerm {const U8: u8 = 0;const U16: u16 = 0;const U32: u32 = 0;const U64: u64 = 0;#[cfg(feature = "i128")]const U128: u128 = 0;const USIZE: usize = 0;const I8: i8 = 0;const I16: i16 = 0;const I32: i32 = 0;const I64: i64 = 0;#[cfg(feature = "i128")]const I128: i128 = 0;const ISIZE: isize = 0;#[inline]fn to_u8() -> u8 {0}#[inline]fn to_u16() -> u16 {0}#[inline]fn to_u32() -> u32 {0}#[inline]fn to_u64() -> u64 {0}#[cfg(feature = "i128")]#[inline]fn to_u128() -> u128 {0}#[inline]fn to_usize() -> usize {0}#[inline]fn to_i8() -> i8 {0}#[inline]fn to_i16() -> i16 {0}#[inline]fn to_i32() -> i32 {0}#[inline]fn to_i64() -> i64 {0}#[cfg(feature = "i128")]#[inline]fn to_i128() -> i128 {0}#[inline]fn to_isize() -> isize {0}
}
impl<U: Unsigned, B: Bit> Unsigned for UInt<U, B> {const U8: u8 = B::U8 | U::U8 << 1;const U16: u16 = B::U8 as u16 | U::U16 << 1;const U32: u32 = B::U8 as u32 | U::U32 << 1;const U64: u64 = B::U8 as u64 | U::U64 << 1;#[cfg(feature = "i128")]const U128: u128 = B::U8 as u128 | U::U128 << 1;const USIZE: usize = B::U8 as usize | U::USIZE << 1;const I8: i8 = B::U8 as i8 | U::I8 << 1;const I16: i16 = B::U8 as i16 | U::I16 << 1;const I32: i32 = B::U8 as i32 | U::I32 << 1;const I64: i64 = B::U8 as i64 | U::I64 << 1;#[cfg(feature = "i128")]const I128: i128 = B::U8 as i128 | U::I128 << 1;const ISIZE: isize = B::U8 as isize | U::ISIZE << 1;#[inline]fn to_u8() -> u8 {B::to_u8() | U::to_u8() << 1}#[inline]fn to_u16() -> u16 {u16::from(B::to_u8()) | U::to_u16() << 1}#[inline]fn to_u32() -> u32 {u32::from(B::to_u8()) | U::to_u32() << 1}#[inline]fn to_u64() -> u64 {u64::from(B::to_u8()) | U::to_u64() << 1}#[cfg(feature = "i128")]#[inline]fn to_u128() -> u128 {u128::from(B::to_u8()) | U::to_u128() << 1}#[inline]fn to_usize() -> usize {usize::from(B::to_u8()) | U::to_usize() << 1}#[inline]fn to_i8() -> i8 {B::to_u8() as i8 | U::to_i8() << 1}#[inline]fn to_i16() -> i16 {i16::from(B::to_u8()) | U::to_i16() << 1}#[inline]fn to_i32() -> i32 {i32::from(B::to_u8()) | U::to_i32() << 1}#[inline]fn to_i64() -> i64 {i64::from(B::to_u8()) | U::to_i64() << 1}#[cfg(feature = "i128")]#[inline]fn to_i128() -> i128 {i128::from(B::to_u8()) | U::to_i128() << 1}#[inline]fn to_isize() -> isize {B::to_u8() as isize | U::to_isize() << 1}
}

二、Unsigned Trait 定义

Unsigned 是一个标记 trait(marker trait),用于表示编译时的无符号整数。它要求实现者必须:

  • 实现 Sealed trait(防止外部实现)

  • 实现 Copy 和 Default

  • 具有 'static 生命周期

它定义了一系列关联常量和方法,用于将编译时数字转换为运行时数字:
关联常量:

  • U8, U16, U32, U64, U128, USIZE:对应各种无符号整数类型的值

  • I8, I16, I32, I64, I128, ISIZE:对应各种有符号整数类型的值

方法:

  • to_u8(), to_u16(), …, to_isize():返回对应类型的值

三、UTerm 的实现

UTerm 表示数字 0,所以所有关联常量和方法都返回 0。

四、UInt<U, B> 的实现

UInt<U, B> 是一个类型级别的数字表示,其中:

  • U 是一个 Unsigned 类型,表示高位部分

  • B 是一个 Bit 类型(可以是 B0 或 B1),表示最低位

这种表示方法实际上是二进制表示。例如:

  • UInt<UTerm, B1> 表示 1

  • UInt<UInt<UTerm, B1>, B0> 表示 10(二进制)即 2(十进制)

实现细节:

对于每个关联常量和方法,计算方式都是:


B::U8 | U::U8 << 1

这相当于:

  1. 将高位部分 U 左移一位(相当于乘以 2)
  2. 加上最低位 B 的值

例如,对于数字 3(二进制 11):

  • 表示为 UInt<UInt<UTerm, B1>, B1>

  • 计算 U8:B1::U8 | UInt<UTerm, B1>::U8 << 1 = 1 | (1 << 1) = 1 | 2 = 3

五、示例解释

文档中的示例:


use typenum::{Unsigned, U3};assert_eq!(U3::to_u32(), 3);
assert_eq!(U3::I32, 3);
  • U3 实际上是 UInt<UInt<UTerm, B1>, B1>

  • 当调用 to_u32() 或访问 I32 时,会递归计算得到值 3

六、特点

这种设计允许在编译时进行数值计算,常用于:

  • 数组长度的类型级验证

  • 矩阵维度的类型级检查

  • 其他需要编译时数值计算的场景

七、性能

由于所有计算都在编译时完成,运行时没有任何开销。生成的代码就像直接使用了常量一样高效。

这种类型级别的数字表示是 Rust 泛型编程和类型系统强大能力的典型体现。

八、改进建议

  1. 移除 #[cfg(feature = “i128”)]
    由于 Rust 1.26+ 已经稳定支持 i128/u128,不再需要 feature gate 来控制其可用性,可以移除所有 #[cfg(feature = “i128”)] 条件编译。
  2. 合并 Unsigned 相关定义到 uint.rs
    UInt 结构体(表示非零无符号整数)和 UTerm(表示零)都是用于无符号整数计算,可以将它们的定义、Unsigned trait 及其实现放在同一个文件(如 uint.rs),而不是分散在 marker_traits.rs 和 uint.rs 中。
    其优点:
  • 减少文件跳转,提高可读性

  • 逻辑相关的代码放在一起,便于维护

  • 更符合 Rust 的模块化设计(类型 + trait + 实现放在一起)

  1. 提供 From 转换

允许从 UTerm 和 UInt 转换到基本整数类型,方便使用:


impl From<UTerm> for u8 {fn from(_: UTerm) -> u8 { 0 }
}impl<U: Unsigned, B: Bit> From<UInt<U, B>> for u8 {fn from(n: UInt<U, B>) -> u8 {B::U8 | U::to_u8() << 1}
}

这样用户可以直接:

let x: u8 = U3::into();  // 而不是 U3::to_u8()
  1. 为 Unsigned 增加 ZERO 和 ONE 常量

由于无符号整数一定有 0 和 1,可以在 trait 中定义这两个常量,方便通用代码使用:


pub trait Unsigned: Sealed + Copy + Default + 'static {const ZERO: Self;const ONE: Self;// ...
}

然后分别在 UTerm 和 UInt 中实现:


impl Unsigned for UTerm {const ZERO: Self = UTerm;const ONE: Self = UInt<UTerm, B1>;  // 需要确保 UInt<UTerm, B1> 是 1
}impl<U: Unsigned, B: Bit> Unsigned for UInt<U, B> {const ZERO: Self = UTerm;  // 可能需要调整,或提供 From<UTerm>const ONE: Self = UInt<UTerm, B1>;
}
http://www.dtcms.com/a/337893.html

相关文章:

  • Ansible 部署LNMP
  • shell脚本实现读取ini键值
  • 部署过程 99年证书
  • Servlet上传文件
  • 亚马逊新手突围:从流量破冰到持续出单
  • ACCESS窗体如何导出到文件,导入另一个工程?
  • java基础总结
  • mysql 主从架构详解
  • label studio标注时序数据
  • 《Unity Shader入门精要》学习笔记二
  • css中px转rem的计算公式
  • 设置独立显卡,解决游戏卡又慢
  • 【opencv-Python学习笔记(6):阈值处理】
  • 深入理解 depot_tools:Chromium 源码开发全流程(fetch/gclient/git cl 使用详解与踩坑经验)
  • Effective C++ 条款49:了解new-handler的行为
  • JAVA经典面试题:数据库调优
  • 算法题——字符串
  • input 标签的宽度根据内容自动调整
  • 电梯的构造|保养|维修视频全集_电梯安全与故障救援(课程下载)
  • JSX本质是什么
  • AI行业应用深度报告:金融、医疗、教育、制造业落地案例
  • Docker之redis安装
  • linux中的hostpath卷、nfs卷以及静态持久卷的区别
  • 使用websockets中的一些问题和解决方法
  • 数据结构04(Java)-- ( 归并排序及其时间复杂度)
  • gflags框架安装与使用
  • 手机视频怎么提取音频?3步转成MP3,超简单!
  • Vue 中 v-for 的使用及 Vue2 与 Vue3 的区别
  • Vue 3中watch的返回值:解锁监听的隐藏技巧
  • Navicat 无法登录时找回 SQL 文件的方法