类型转换,第一部分
我们已经多次强调过,Rust 不会为整数执行隐式类型转换。
那么,如何进行显式转换呢?
as
关键字
你可以使用 as
关键字在整数类型之间进行转换。
as
转换是不会失败的。
例如:
#![allow(unused)] fn main() { let a: u32 = 10; // 将 `a` 转换为 `u64` 类型 let b = a as u64; // 你可以使用 `_` 作为目标类型 // 如果编译器能正确推断出来的话 // 比如: let c: u64 = a as _; }
这种转换的语义是你所期望的:所有 u32
的值都是有效的 u64
值。
截断
如果我们反向进行就会更有趣:
#![allow(unused)] fn main() { // 一个太大以至于无法放入 `u8` 的数字 let a: u16 = 255 + 1; let b = a as u8; }
此程序将无问题运行,因为 as
转换是绝对不会失败的。
但 b
的值是多少呢?
从较大的整数类型转换到较小的类型时,Rust 编译器会执行截断。
要了解发生了什么,我们先来看 256u16
在内存中是如何表示的,即一系列位:
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
| | |
+---------------+---------------+
高8位 低8位
转换为 u8
时,Rust 编译器将保留 u16
内存表示的最后8位:
0 0 0 0 0 0 0 0
| |
+---------------+
低8位
因此,256 as u8
等于 0
。这在大多数场景下...不太理想。
实际上,如果编译器看到你试图进行会导致截断的字面值转换,它会主动阻止你:
错误:字面值超出 `i8` 的范围
|
4 | let a = 255 as i8;
| ^^^
|
= 注意:字面值 `255` 无法放入范围为 `-128..=127` 的 `i8` 类型中
= 帮助:考虑使用类型 `u8` 代替
= 注意:默认启用了 `#[deny(overflowing_literals)]`
建议
总的来说,使用 as
转换要非常小心。
仅限于从较小类型转换到较大类型时使用。若要从较大整数类型转换到较小的整数类型,请依赖于我们将在课程后期探索的可失败的转换机制。
局限性
令人惊讶的行为并不是 as
转换的唯一缺点。它也相当有限:你只能依靠 as
转换用于原始类型和其他少数特殊情况。
在处理复合类型时,你将需要依赖于不同的转换机制(可失败的 和 不可失败的),我们将在后续内容中探讨。
参考资料
- 本节练习位于
exercises/02_basic_calculator/10_as_casting
进一步阅读
- 查阅 Rust 官方参考文档的这一部分,了解每种源类型和目标类型组合下
as
转换的确切行为,以及所有允许的转换列表。