整数是没有小数部分的数。它们在机器中表示为二进制位的模式。
整数可以是有符号的,也可以是无符号的。有无符号是指,预留数字中的一位来表示该数是否为负数。
所有整数都有一个位宽,也就是组成该数的二进制位的数量。它会影响该整数类型能表示的最大值。
例如,最常见的整数类型之一是u8:一个无符号的 8 位整数。你可能认为这个类型就是一个字节。它的最小值为 0,最大值为 255。
Rust 有 12 种整数原生类型,按位宽和有无符号划分:
| Unsigned | Signed |
|---|---|
u8 |
i8 |
u16 |
i16 |
u32 |
i32 |
u64 |
i64 |
u128 |
i128 |
usize |
isize |
整数的位宽总是由u或i后面的数字表示。usize和isize很特殊:它们与目标机器上的指针宽度相同。这意味着在 64 位架构上,usize和isize是 64 位宽;而在 32 位架构上,它们是 32 位宽。
一般来说,如果你只需要表示某个数字,就用i32:32 位有足够宽的范围,相对不容易溢出,而且有符号数比无符号数更少让人意外。i32相当于 C 语言中的long,或者 Java 中的int。如果你使用数值字面量并且没有显式标注类型,它默认会是i32。
如果你处理二进制数据,最方便的是按字节处理:&[u8]或Vec<u8>。
Rust 使用usize来表示集合的大小和索引。这是因为理论上计算机只能寻址usize::MAX字节的内存,所以不可能有更大的内存中集合。因此,如果你要大量处理集合,usize会很有用。
如果你的数据放不进 32 位整数,考虑拓宽到 64 位或 128 位整数。如果你的数据放不进 128 位整数,那么可以使用大整数类型,例如num-bigint提供的类型。
16 位整数不太常见,但在针对某些微控制器时可能很有用。
如果你知道你的应用中没有有效的负数情况,最好使用无符号整数而不是有符号整数。计数就是一个很好的例子。
Rust 没有隐式数值转换。如果需要在整数类型之间转换,有两种基本策略:as关键字,以及From和TryFrom trait。
使用as关键字很简单:expr as Type。但是,使用as转换时,有许多注意事项和细微之处需要记住。
基于 trait 的转换稍微复杂一些,但更安全:转换 trait 只在安全的地方实现。例如,i32实现了From<u8>、From<u16>、From<i8>和From<i16>:任何这些类型能表示的值都保证可以在i32中表示。它可以像i32::from(expr)或expr.into()这样使用,其中expr会解析为上述类型之一。i32也实现了TryFrom<u32>、TryFrom<u64>、TryFrom<u128>、TryFrom<usize>、TryFrom<i64>、TryFrom<i128>和TryFrom<isize>。这些转换会显式地成功或溢出,具体取决于值。要使用它们,你需要视情况导入std::convert::TryFrom或std::convert::TryInto trait,然后使用i32::try_from(expr)或expr.try_into(),其中expr解析为合适的类型。
通常更推荐使用基于 trait 的转换而不是as转换,尤其是在从更宽的类型转换为更窄的类型时。基于 trait 的转换比as转换的性能开销略高,但无关紧要:除非在极其热点的循环中,否则为了性能而使用as并不值得。