Rust是一种系统级编程语言,注重速度、内存安全和并行性。它提供了丰富的数据类型体系,可以分为两大类:标量(scalar)类型和复合(compound)类型。

标量类型

  1. 整数类型:Rust提供多种大小的有符号和无符号整数类型。例如,i8, i16, i32, i64, i128分别表示8位、16位、32位、64位和128位的有符号整数;u8, u16, u32, u64, u128表示相应的无符号整数。

  2. 浮点类型:Rust支持两种主要的浮点数类型,f32f64,分别代表32位和64位浮点数。

  3. 布尔类型:布尔类型只有一个关键字bool,它可以有两个值:truefalse

  4. 字符类型:Rust的char类型用于表示单个Unicode字符,不仅限于ASCII。

复合类型

  1. 元组(Tuple):允许将多个不同类型的值组合在一起。可以通过模式匹配或使用.操作符后跟索引来访问元组中的元素。

  2. 数组(Array):一个固定大小的相同类型元素集合。数组的所有元素必须是同一类型。定义方式为[type; size]

  3. 向量(Vector):与数组类似,但可以在运行时改变大小。它是通过标准库中的Vec<T>类型实现的,提供了动态调整大小的功能。

除了上述基本类型之外,Rust还允许通过结构体(structs)、枚举(enums)等自定义复杂的数据类型,并且支持使用泛型来编写更加通用和可重用的代码。


一、标量类型(Scalar Types)

标量类型表示单个值,包括整数、浮点数、布尔值和字符。


1. 整数类型(Integers)

特点:

  • 有符号i开头)和无符号u开头)两种类型。
  • 支持多种位数:i8/u8, i16/u16, i32/u32, i64/u64, i128/u128
  • 默认类型i32(32位有符号整数)和u32(32位无符号整数)。

示例代码:

rust 复制代码
fn main() {
    // 显式类型标注
    let signed: i32 = 42;       // 有符号整数(默认i32)
    let unsigned: u8 = 255;     // 无符号整数(u8最大值255)

    // 类型推断(无需显式标注)
    let default_int = 100;      // 推断为i32
    let default_uint = 100u8;   // 显式标注u8

    // 溢出检查(编译时报错)
    // let overflow = 256u8; // 错误:超过u8的范围(0-255)
}

下表显示了Rust 中的内置的整数类型:

长度 有符号类型 无符号类型
8 位 i8 u8
16 位 i16 u16
32 位 i32 u32
64 位 i64 u64
128 位 i128 u128
视架构而定 isize usize

每个有符号类型规定的数字范围是 -(2n - 1) ~ 2n - 1 - 1,其中 n 是该定义形式的位长度。因此 i8 可存储数字范围是 -(27) ~ 27 - 1,即 -128 ~ 127。无符号类型可以存储的数字范围是 0 ~ 2n - 1,所以 u8 能够存储的数字为 0 ~ 28 - 1,即 0 ~ 255。

此外,isize 和 usize 类型取决于程序运行的计算机 CPU 类型: 若 CPU 是 32 位的,则这两个类型是 32 位的,同理,若 CPU 是 64 位,那么它们则是 64 位。

注意事项:

  • 溢出检查:Rust在编译时会检查常量是否超出类型范围。
  • 选择类型:根据数值范围选择合适位数(如u8适合0-255的计数器)。

2. 浮点类型(Floats)

特点:

  • 支持两种精度:f32(32位单精度)和f64(64位双精度)。
  • 默认类型f64

示例代码:

rust 复制代码
fn main() {
    let single_precision: f32 = 3.14; // 显式f32
    let double_precision = 2.71828;   // 推断为f64

    // 科学计数法
    let scientific = 6.022e23;        // 6.022 × 10^23
}

注意事项:

  • 精度问题:浮点数计算可能有微小误差(如0.1 + 0.2 != 0.3)。
  • 避免在浮点数上测试相等性
  • 选择类型f32适合对内存敏感的场景(如游戏开发),f64适合需要高精度的场景。

例如,下列代码会崩溃:

rust 复制代码
// assertion failed: 0.1 + 0.2 == 0.3 
fn main() {
  // 断言0.1 + 0.2与0.3相等
  assert!(0.1 + 0.2 == 0.3);
}

3. 布尔类型(Booleans)

特点:

  • 只有两个值:truefalse
  • 类型为bool

示例代码:

rust 复制代码
fn main() {
    let is_rust_amazing = true;
    let is_rust_easy = false;

    // 逻辑运算
    let and_result = is_rust_amazing && is_rust_easy; // false
    let or_result = is_rust_amazing || is_rust_easy;  // true
    let not_result = !is_rust_amazing;                // false
}

注意事项:

  • 短路运算&&||会短路(若前一个条件已确定结果,后续条件不执行)。

4. 字符类型(Chars)

特点:

  • 表示单个Unicode标量值,占4字节。
  • 使用单引号'包裹,支持表情符号、中文等。

示例代码:

rust 复制代码
fn main() {
    let letter = 'A';         // ASCII字符
    let emoji = '🎉';         // Unicode字符
    let chinese = '你';        // 中文字符

    // 转义字符
    let tab = '\t';           // 制表符
    let newline = '\n';       // 换行符
    let heart = '\u{2665}';  // Unicode代码点(♥)
}

注意事项:

  • 编码要求:字符和字符串必须使用UTF-8编码,否则编译报错。
  • ASCII优化:若仅需ASCII字符,可用u8类型(1字节)并用b'A'表示。

二、复合类型(Compound Types)

复合类型由多个值组合而成,包括元组(Tuple)和数组(Array)。


1. 元组(Tuples)

特点:

  • 固定长度,元素类型可以不同。
  • 通过索引(.0, .1等)或解构访问元素。

示例代码:

rust 复制代码
fn main() {
    // 声明元组
    let tuple = (500, 6.4, 'R'); // 类型为(i32, f64, char)

    // 解构元组
    let (x, y, z) = tuple;
    println!("x = {}, y = {}, z = {}", x, y, z); // x = 500, y = 6.4, z = R

    // 索引访问
    println!("First element: {}", tuple.0); // 500

    // 单元素元组(注意逗号)
    let single = (42,); // 类型为(i32,)
}

注意事项:

  • 单位类型:空元组()表示无值,常用于函数返回。
  • 不可变性:元组元素不可变(除非显式使用mut)。

2. 数组(Arrays)

特点:

  • 固定长度,所有元素类型相同。
  • 通过方括号[]声明,支持三种初始化方式。

示例代码:

rust 复制代码
fn main() {
    // 方式1:推断类型和长度
    let arr1 = [1, 2, 3, 4]; // 类型为[i32; 4]

    // 方式2:显式类型和长度
    let arr2: [f64; 3] = [0.1, 0.2, 0.3];

    // 方式3:重复元素
    let arr3 = [true; 5];    // [true, true, true, true, true]

    // 访问元素
    println!("Third element: {}", arr1[2]); // 3(索引从0开始)

    // 数组长度
    println!("Length: {}", arr1.len()); // 4
}

注意事项:

  • 长度固定:无法动态扩容,需改用Vec<T>(向量,标准库类型)。
  • 索引越界:运行时会panic(如arr[4]在长度为3的数组中会报错)。

三、常见问题与最佳实践

1. 类型推断与显式标注

  • 类型推断:Rust会根据赋值自动推断类型(如let x = 5;推断为i32)。
  • 显式标注:当类型不明确时需显式标注:
    rust 复制代码
    let answer: u32 = "42".parse().expect("Not a number!");

2. 运算符

  • 算术运算+, -, *, /, %
  • 复合赋值+=, -=, *=, /=(如x += 1等价于x = x + 1)。
  • ++--:Rust不支持,避免代码歧义。

3. 编码与内存

  • 字符编码:所有字符串和字符必须为UTF-8。
  • 内存优化:选择合适类型(如u8代替char存储ASCII字符)。

四、练习与验证

练习1:数据类型转换

rust 复制代码
fn main() {
    let decimal = 68.42_f32; // 显式标注f32类型
    let integer = decimal as u8; // 转换为u8(截断为68)
    println!("Converted to u8: {}", integer);
}

练习2:元组与数组嵌套

rust 复制代码
fn main() {
    // 嵌套元组和数组
    let complex_tuple = ([1, 2], (true, 'A'));
    println!("First element of array: {}", complex_tuple.0[0]); // 1
}