数据类型
- 在 Rust 中,除了原生的基础类型(如 i32, f64, char, bool)和元组/数组外,几乎所有复杂的数据组织形式都是靠
struct、enum和union撑起来的
标量类型
整型
语法: 类型性质 + 位数
- 无符号:
0到2^n - 1 - 有符号:
-2^(n-1)到2^(n-1) - 1
| 长度 | 无符号 | 有符号 | 范围 |
|---|---|---|---|
8-bit | u8 | i8 | 0-255 或 -128-127 |
16-bit | u16 | i16 | 0-65,535 或 -32,768-32,767 |
32-bit | u32 | i32(默认) | 0-约 42.9 亿 或 约 -21.4 亿-21.4 亿 |
64-bit | u64 | i64 | 0-1.84 x 10^19 或 -9.22 x 10^18-9.22 x 10^18 |
128-bit | u128 | i128 | |
架构相关 | usize | isize |
i代表Integer(整数),特指Signed Integer(有符号整数).它可以表示正数、负数和零.u代表Unsigned(无符号),特指Unsigned Integer(无符号整数).它只能表示非负数(0 和正数).- 数组索引必须是
usize
整型字面值
| 数字字面值 | 例子 |
|---|---|
Decimal (十进制) | 98_222 |
Hex (十六进制) | 0xff |
Octal (八进制) | 0o77 |
Binary (二进制) | 0b1111_0000 |
Byte (单字节字符,仅限于u8) | b'A' = 65 |
整数溢出
rust
let x: u8 = 255;
let y = x + 1;
// Debug模式 会 panic
// Release模式 会变成 0字面量后缀类型标注
rust
let x = 10u8; // 等于 let x: u8 = 10;
let y = 20i64; // 等于 let y: i64 = 20;
let z = 3.14f32; // 等于 let z: f32 = 3.14;浮点型
| 长度 | 类型 | 精度 | 范围 |
|---|---|---|---|
32-bit | f32 单精度浮点数 | 约 6 ~ 9 位 | -1.18*10^38-3.40*10^38 |
64-bit | f64 双精度浮点数(默认) | 约 15 ~ 17 位 | -2.23*10^308-1.79*10^308 |
f32: 占用 32 位(4 字节).f64: 占用 64 位(8 字节),正好是f32的两倍.
例子: 如果你计算圆周率,
f32可能只能精确到 3.141592,而f64能到 3.141592653589793
布尔类型 bool
true和false是仅有的两个值- 占 1 字节(8 bit)
rust
let t = true;
let f: bool = false;
if true { } // ✅
if 1 { } // ❌ 不允许,整数不能作为布尔条件;Rust 不会将整数隐式转换为 bool
if 1 != 0 { } // ✅ 需要显式比较- 布尔值可以通过比较运算符(
==、<、>等)生成 - 布尔值可以通过逻辑运算符(
&&、||、!)组合
rust
let x = 5;
let y = x > 3 && x < 10; // y = true字符类型 char
char 类型是语言中最原始的字母类型
- 是一个
Unicode标量值(Unicode scalar value) - 占 4 字节(32 bit)
- 使用单引号
''声明
rust
let z: char = 'ℤ'; // with explicit type annotation
let c = 'A'; // 1 字节表示,但占 4 字节内存
let emoji = '😻'; // 也是 4 字节char 与 String 的区别
| 特性 | char | String |
|---|---|---|
| 声明符号 | 单引号 '' | 双引号 "" |
| 存储内容 | 单个字符 | 字符序列 |
| 大小 | 固定 4 字节 | 动态(堆分配) |
| 类型性质 | 原始类型 | 复杂类型 |
| Unicode表示 | 单个码位 | 多个码位序列 |
复合类型
Rust 有两个原生的复合类型: 元组(tuple)和数组(array)
元组 tuple
- 将多个不同类型的值组合进一个复合类型的主要方式
- 元组长度是固定的
- 元组每个元素的所有权是独立的
- 本质是一个没有名字的结构体
rust
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // 模式匹配取值: 解构(destructuring)
let first = tup.0; // 点号(.)取值
let mut tup1 = (1, 2, 3);
tup1.0 = 10; // ✅ 可以改变元组值空元组
Rust 的"单元类型"(unit type),使用 () 表示,等价于 JavaScript 的 undefined,很多函数默认返回它.
rust
let unit: () = ();数组 array
- 数组中的每个元素的类型必须相同
- 数组长度是固定的
- 数组的所有权是整体的
rust
let a = [1, 2, 3, 4, 5];
let a: [i32; 5] = [1, 2, 3, 4, 5];
let a = [3; 5]; // 等于 let a = [3, 3, 3, 3, 3];
let first = a[0]; // [] 取值
let mut a = [1, 2, 3];
a[0] = 10; // ✅ 可以改变元素值数组与向量的区别
| 特性 | array | Vec(向量) |
|---|---|---|
| 长度 | 固定 | 动态 |
| 内存分配 | 栈 | 堆 |
| 语法 | [T; n] | Vec<T> |
| 索引 | usize 类型 | usize 类型 |
| 越界行为 | panic | panic |
额外补充
as 基本类型转换
Rust 不会自动进行类型转换,需要使用 as 关键字显式转换.截断和溢出行为由目标类型决定:
rust
let x: i32 = 42;
let y = x as f64; // i32 → f64
let z = 3.99f64 as i32; // f64 → i32,截断小数部分 → 3(不四舍五入)
let b = 300u32 as u8; // 超出范围时截断(300 % 256 = 44)
let c = 'A' as u32; // char → u32(Unicode 码位: 65)
let d = 65u8 as char; // u8 → char → 'A'
as只能用于基本数值类型和char/指针之间的转换,不能用于String/&str等复杂类型(需用.to_string()/.parse()等方法).
isize 和 usize
isize/usize的大小取决于目标平台的指针宽度: 32位系统为4字节,64位系统为8字节.usize是数组索引和集合长度的标准类型(len()、[]索引均返回/接受usize).isize常用于指针偏移量计算(负偏移时派上用场).
整数溢出的安全处理方法
除了 Debug 模式 panic / Release 模式截断外,标准库提供了四组安全方法:
checked_add(): 安全加法,溢出时返回None,适合需要明确处理溢出情况的场景saturating_add(): 饱和加法,溢出时结果固定在该类型的最大值或最小值,适合需要边界保护的场景wrapping_add(): 环绕加法,溢出时按二进制环绕处理,行为与Release模式一致,适合需要循环计数的场景overflowing_add(): 返回元组(result, is_overflow),同时获得结果和溢出标志,适合需要记录溢出事件的场景
使用建议: 根据具体需求选择合适的方法,优先考虑 checked_add() 以获得更好的错误处理能力.
rust
let x: u8 = 255;
x.checked_add(1) // → None(溢出返回 None)
x.saturating_add(1) // → 255(饱和: 钉在最大/最小值)
x.wrapping_add(1) // → 0(环绕: 和 Release 行为一致)
x.overflowing_add(1) // → (0, true)(返回结果和是否溢出的元组)