一、为什么 Rust 的数据类型这么"严谨"?
专业名词释义:
- 类型安全(Type Safety):Rust 在编译期就强制检查类型兼容性,不允许隐式转换(implicit conversion)。这与 C/C++ 的"弱类型"形成鲜明对比,是 Rust 内存安全的核心保障之一。
- 零成本抽象(Zero-Cost Abstractions):所有类型检查都在编译期完成,运行时无额外开销。
用法:所有变量必须有明确类型(可推断),防止运行时类型错误。
注意事项与最佳实践:
- Rust 不提供隐式转换,必须用
as显式转换(详见第五节)。 - 好处:编译器帮你杜绝 99% 的类型 Bug;坏处:初学者会频繁看到"mismatched types"错误------这是正常现象,坚持下去你就爱上它了。
- 进阶:结合所有权系统(Ownership),类型安全让并发编程几乎无数据竞争。
二、Rust 简单示例(先跑起来!)
专业名词释义:
- 宏(Macro) :以
!结尾的特殊函数(如println!、assert_eq!),在编译期展开为真实代码。不是普通函数。
用法:
rust
fn main() {
let a: i32 = 1;
let b = 2; // 类型推断
println!("a = {}", a);
println!("hello, world");
assert_eq!(2, b);
}
注意事项:
assert_eq!仅在测试/调试中使用,生产代码建议用debug_assert_eq!(仅 Debug 模式生效)。- 最佳实践:宏能大幅提升代码可读性,但过度使用会让编译时间变长。
三、基本数据类型全家福(带深度解析)
专业名词释义:
- 原生类型(Primitive Types / Scalar Types):语言内置的最基础类型,无需引入任何库。
- 整数溢出(Integer Overflow):运算结果超出类型表示范围的行为。
- Unicode 标量值(Unicode Scalar Value) :
char的核心定义,指一个有效的 Unicode 码点(U+0000 到 U+10FFFF),不含代理对。
用法示例(官方推荐写法):
rust
// 整型
let decimal = 98_222; // 可读性下划线
let hex = 0xff;
let octal = 0o77;
let binary = 0b1111_0000;
let byte = b'A'; // u8 字节字面量
// 浮点
let pi: f64 = 3.1415926; // 默认 f64
let f: f32 = 3.0;
// 字符与布尔
let c: char = '😻';
let heart = true;
注意事项与最佳实践(重点!):
-
整数溢出行为 (Rust 官方最新标准):
-
Debug 模式 :溢出直接
panic!(程序崩溃,利于调试)。 -
Release 模式 :两补码环绕(wrapping) ,例如
u8的 255 + 1 = 0。不要依赖此行为! -
安全处理方式 (强烈推荐):
rustlet x = 255u8; let y = x.checked_add(1).unwrap_or(0); // 返回 Option let z = x.wrapping_add(1); // 明确环绕 let s = x.saturating_add(1); // 饱和到最大值
-
-
char 类型深度 :固定 4 字节 ,表示 Unicode 标量值。不是"用户可见字符"(grapheme cluster) !
- 示例:
'😻'是 1 个char,但带组合符号的 emoji 可能需要多个char。 - 坑点:处理字符串时用
str::chars()(标量值)还是unicode-segmentation库的graphemes()(用户感知字符)?取决于需求。
- 示例:
-
isize / usize :平台相关(32/64 位),索引集合必须用,否则编译错误。
-
最佳实践 :整型默认
i32,浮点默认f64;永远不要用as做"大概齐"转换。
| 类型 | 最小值 | 最大值 | 占用字节 |
|---|---|---|---|
| u8 | 0 | 255 | 1 |
| i32 | -2³¹ | 2³¹-1 | 4 |
| f64 | - | - | 8 |
| char | U+0000 | U+10FFFF | 4 |
| bool | false | true | 1 |
四、变量声明与可变性(Rust 灵魂!)
专业名词释义:
- 不可变绑定(Immutable Binding) :
let x = 5;默认行为,一旦绑定就不可修改。 - 变量遮蔽(Shadowing) :用同名
let重新绑定,创建新变量,原变量被暂时"隐藏"。 - 可变性(Mutability) :
mut关键字显式声明变量可修改。
用法示例(官方经典):
rust
let mut x = 5; // 可变
x = 6;
let x = 5; // 不可变
let x = x + 1; // 遮蔽!类型可变
let x = x * 2; // 继续遮蔽
注意事项与最佳实践:
- 为什么默认不可变?(Rust 哲学):编译器保证"某个值不会被意外修改",极大提升并发安全和代码可读性。
- 遮蔽 vs mut :
- 遮蔽允许类型转换 (
let spaces = " "; let spaces = spaces.len(););mut不允许。 - 遮蔽适合转换链 (如解析字符串 → 数字);
mut适合真正需要多次修改的场景。
- 遮蔽允许类型转换 (
- 坑点:深层嵌套遮蔽会降低可读性,建议不超过 2 层。
- 最佳实践 :除非必要,永远不用
mut------ "能用遮蔽解决的,就别用 mut"。
五、类型转换(必须显式!)
专业名词释义:
- 显式转换(Casting) :使用
as关键字进行的类型转换。
用法:
rust
let decimal = 65.4321_f32;
let integer = decimal as u8; // 65(丢失精度)
let character = integer as char; // 'A'
注意事项:
- 小范围转大范围安全;大转小会截断或溢出。
as在 Release 模式也可能导致意外结果 ------ 推荐用TryFrom/Fromtrait 做安全转换(u32::try_from(value))。- 进阶 :指针转换、函数指针转换等属于高级主题,日常开发几乎用不到
as做指针操作。
六、复合类型(数组 + 元组 + 切片)
专业名词释义:
- 数组(Array):固定长度、同类型元素的集合,栈上分配。
- 元组(Tuple):固定长度、异构类型的复合类型。
- 单元类型(Unit Type) :
(),唯一值也是(),表示"无返回值"。 - 切片(Slice):不拥有数据的引用类型,只包含指针 + 长度。
用法示例:
rust
// 数组
let arr: [i32; 3] = [1, 2, 3];
let zeros = [0; 500];
// 元组解构
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
// 切片(函数参数推荐)
fn first_word(s: &[char]) -> &[char] { ... }
注意事项与最佳实践:
- 数组 vs 切片 :数组长度编译期已知(性能更好);切片长度运行时决定(灵活)。函数参数永远用切片
&[T]而不是&[T; N]。 - 元组 :适合返回多个值(
-> (i32, bool)),但超过 3 个字段建议用结构体(struct)。 - 单元类型 :函数无
return时隐式返回()------ 这是 Rust "一切皆表达式"的体现。 - 坑点 :切片索引必须在运行时检查,超出范围会 panic(
s[100])。
七、常量 & 静态变量(全局数据)
专业名词释义:
- 常量(Const Item):编译期求值的不可变值,无固定内存地址,可内联。
- 静态变量(Static Item) :拥有固定内存地址的全局变量,
'static生命周期。
用法示例:
rust
const MAX: u32 = 100_000; // 推荐
static LEVEL: u32 = 0;
// 可变静态(极少用)
static mut COUNTER: u32 = 0; // 必须 unsafe 访问
注意事项与最佳实践(深度重点):
- const vs static 核心区别 (Rust Reference 最新版):
const是值 (可重复内联,无地址);static是内存位置(全局唯一地址)。- 需要"单例"或大数组时用
static;普通常量永远用const。
- static mut 危险 :必须在
unsafe {}块中读写,多线程下易数据竞争 (Undefined Behavior)。- 替代方案:
std::sync::atomic或std::sync::OnceLock(Rust 最新稳定版推荐,用于懒初始化全局配置)。
- 替代方案:
- const 限制 :只能是编译期常量表达式,不能调用普通函数(除非
const fn)。 - 最佳实践 :全局配置用
const,需要运行时初始化的全局用OnceLock。
八、本章小结 + 进阶练习
学完本章你应该能做到:
- 熟练掌握所有原生类型 + 溢出/Unicode 坑点
- 灵活运用
mutvs 遮蔽 - 区分数组/切片/元组的适用场景
- 正确选择
const/static,并知道static mut的风险
进阶练习(建议立刻敲代码):
- 实现一个安全的整数加法函数(使用
checked_add)。 - 用元组 + 切片写一个返回"首尾元素"的函数。
- 声明一个
static全局配置,用OnceLock初始化(不许用mut)。
(完)