一、源碼
這段代碼是 Rust 中用于實現編譯時無符號整數的核心部分。它定義了一個 Unsigned trait 并為兩種類型實現了該 trait:UTerm(表示零)和 UInt<U, B>(表示非零數字)。
- 定義(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;
}
- 實現
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
這相當于:
- 將高位部分 U 左移一位(相當于乘以 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 泛型編程和類型系統強大能力的典型體現。
八、改進建議
- 移除 #[cfg(feature = “i128”)]
由于 Rust 1.26+ 已經穩定支持 i128/u128,不再需要 feature gate 來控制其可用性,可以移除所有 #[cfg(feature = “i128”)] 條件編譯。 - 合并 Unsigned 相關定義到 uint.rs
UInt 結構體(表示非零無符號整數)和 UTerm(表示零)都是用于無符號整數計算,可以將它們的定義、Unsigned trait 及其實現放在同一個文件(如 uint.rs),而不是分散在 marker_traits.rs 和 uint.rs 中。
其優點:
-
減少文件跳轉,提高可讀性
-
邏輯相關的代碼放在一起,便于維護
-
更符合 Rust 的模塊化設計(類型 + trait + 實現放在一起)
- 提供 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()
- 為 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>;
}