在rust中,数据类型分为两大类:
标量类型:代表一个单一的值。
复合类型:可以把多个值组合成一个类型。
Rust 是一门静态类型语言,也就是说,所有变量的类型在编译期就必须完全确定。通常编译器能通过你的代码自动推断类型,但一旦出现歧义,你就必须手工标注类型。
let guess: u32 = "42".parse().expect("Not a number!");// 这里必须标明 u32 因为rust无法推断出来另外,Rust 的类型是强类型的,不会悄悄做隐式类型转换(比如把一个整数自动转成浮点数)。你要是想转,必须用 as 或用 From/Into 等 trait 显式转换。
标量类型
标量类型表示单一值。Rust 有四种基本标量类型:整型、浮点型、布尔型、字符型。
1. 整型(Integer)
整型是最常用的数字类型,Rust 按长度和有无符号分成很多种:
| 长度 | 有符号 | 无符号 |
|---|---|---|
| 8 位 | i8 | u8 |
| 16 位 | i16 | u16 |
| 32 位 | i32 | u32 |
| 64 位 | i64 | u64 |
| 128 位 | i128 | u128 |
| 架构相关 | isize | usize |
isize 和 usize 在 64 位机器上就是 64 位,在 32 位机器上是 32 位,主要用于集合的索引和长度。
默认的整数类型是 i32,性能和兼容性平衡得最好。
整数字面量可以写成多种进制,还能加下划线提升可读性:
let a = 98_222; // 十进制
let b = 0xff; // 十六进制
let c = 0o77; // 八进制
let d = 0b1111_0000; // 二进制
let e = b'A'; // 字节字面量 (u8)2. 浮点型(Floating-Point)
Rust 有 f32(单精度)和 f64(双精度)两种。默认是 f64,因为在现代 CPU 上速度和 f32 差不多,但精度更高。
let x = 2.0; // f64
let y: f32 = 3.0; // f32浮点数遵循 IEEE-754 标准。注意,它不能直接判等——这点和所有语言一样,精度问题会导致 0.1 + 0.2 != 0.3。如果需要更精确的小数运算,请用 rust_decimal 或 num-rational 等 crate。
3. 布尔型(Boolean)
和别的语言一样,bool 只有两个值:true 和 false,占用一个字节。
let is_rust_fun: bool = true;它是条件判断的基石,Rust 不会把非布尔值自动转成布尔,比如 if 1 {} 在 Rust 中是编译错误,必须写 if 1 != 0 {}。
4. 字符类型(Char)
Rust 的 char 有点特别:它4 字节,代表一个 Unicode 标量值,范围从 U+0000 到 U+D7FF 和 U+E000 到 U+10FFFF。这意味着它能表示中文、emoji 等任何单个字符。
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';注意 char 用的是单引号,字符串用双引号。它们不能混用,这一点编译器会非常严格地提醒你。
复合类型
复合类型可以把多个值“打包”成一个类型。Rust 里最原始的两个复合类型是元组(tuple)和数组(array)。
元组(Tuple)
元组是把不同类型的几个值组合成一个整体的通用方式,长度固定。
let tup: (i32, f64, u8) = (500, 6.4, 1);解构元组很方便:
let (x, y, z) = tup;
println!("y 的值是: {y}");也可以用句点索引直接访问:
let five_hundred = tup.0;
let six_point_four = tup.1;没有任何动态索引,类型完全不同时,编译器会保证你不会弄混。
元组特殊值:单元(unit),空元组 (),表示没有值。如果一个函数不返回值,它实际上返回的就是 ()。
2. 数组(Array)
数组要求每个元素类型相同,而且长度固定,在栈上分配。它和 vector(Vec<T>,可变长,在堆上)不同。
let a = [1, 2, 3, 4, 5];
let months = ["一月", "二月", "三月", ...];你可以显式指定类型和长度:
let a: [i32; 5] = [1, 2, 3, 4, 5];用方括号初始化为相同值:
let a = [3; 5]; // 等价于 [3, 3, 3, 3, 3]数组访问:
let first = a[0];越界保护:如果你尝试用 a[10] 访问一个长度为 5 的数组,Rust 在运行时会做边界检查,一旦越界直接 panic,而不是像 C 那样默默读写非法内存。这是 Rust 内存安全保障的重要体现。
在需要动态调整大小的场景,应该使用 Vec<T>,但当你明确知道元素数量不变时(比如一周七天、十二个月),数组就是更高效、更安全的选择。