Rust 数据类型

Rust 是一门静态类型语言,数据类型在编译时必须明确,编译器通过类型推断或显式声明确保类型安全。以下是用中文详细讲解 Rust 的数据类型,涵盖标量类型和复合类型,配以示例代码,简洁明了,适合初学者和需要快速复习的开发者。


1. 标量类型(Scalar Types)

标量类型表示单个值,Rust 提供四种主要标量类型:整数、浮点数、布尔值和字符。

1.1 整数类型(Integer Types)

Rust 支持有符号(i)和无符号(u)整数,长度包括 8、16、32、64、128 位,以及架构相关类型 isizeusize

类型描述范围示例(以 i32 和 u32 为例)
i88 位有符号整数-128 到 127
u88 位无符号整数0 到 255
i1616 位有符号整数-32,768 到 32,767
u1616 位无符号整数0 到 65,535
i3232 位有符号整数-2,147,483,648 到 2,147,483,647
u3232 位无符号整数0 到 4,294,967,295
i6464 位有符号整数~ -2^63 到 2^63 – 1
u6464 位无符号整数0 到 2^64 – 1
i128128 位有符号整数~ -2^127 到 2^127 – 1
u128128 位无符号整数0 到 2^128 – 1
isize架构相关有符号32 位系统:同 i32;64 位系统:同 i64
usize架构相关无符号32 位系统:同 u32;64 位系统:同 u64

示例

fn main() {
    let x: i32 = -42; // 有符号整数
    let y: u8 = 255;  // 无符号整数
    let z: usize = 100; // 架构相关,常用作索引
    println!("x = {}, y = {}, z = {}", x, y, z);
}

说明

  • 默认整数类型为 i32(类型推断时)。
  • 整数溢出在调试模式会触发 panic,发布模式会回绕(wrap)。

1.2 浮点数类型(Floating-Point Types)

Rust 有两种浮点类型:f32(单精度)和 f64(双精度)。

类型描述示例值
f3232 位浮点数3.14, -0.001, 2e-3
f6464 位浮点数3.14159265359, 1.0e10

示例

fn main() {
    let pi: f64 = 3.14159265359;
    let small: f32 = 0.0001;
    println!("pi = {}, small = {}", pi, small);
}

说明

  • 默认浮点类型为 f64,因为精度更高且性能接近 f32
  • 支持科学计数法(如 2e-3 表示 0.002)。

1.3 布尔类型(Boolean Type)

Rust 的布尔类型为 bool,只有两个值:truefalse

示例

fn main() {
    let is_active: bool = true;
    let is_zero: bool = false;
    println!("is_active = {}, is_zero = {}", is_active, is_zero);
}

说明

  • 常用于条件判断(如 if 语句)。
  • 布尔值占用 1 字节。

1.4 字符类型(Character Type)

Rust 的 char 类型表示 Unicode 标量值(4 字节),可以存储任意 Unicode 字符(如中文、表情符号等)。

示例

fn main() {
    let c: char = 'A';
    let zh: char = '中';
    let emoji: char = '😊';
    println!("c = {}, zh = {}, emoji = {}", c, zh, emoji);
}

说明

  • 使用单引号 '' 定义字符。
  • 比 C/C++ 的 char(1 字节)更灵活,支持多语言字符。

2. 复合类型(Compound Types)

复合类型将多个值组合成一个类型,Rust 提供元组(Tuple)和数组(Array)。

2.1 元组(Tuple)

元组是固定长度的集合,元素类型可以不同。

示例

fn main() {
    let tup: (i32, f64, char) = (42, 3.14, 'x');
    // 解构
    let (x, y, z) = tup;
    println!("x = {}, y = {}, z = {}", x, y, z);
    // 通过索引访问
    println!("tup.0 = {}", tup.0);
}

说明

  • 元组用圆括号 () 定义。
  • 可以通过解构或索引(如 tup.0)访问元素。
  • 最大长度为 12(受某些限制,如 Debug trait)。

2.2 数组(Array)

数组是固定长度的集合,元素类型必须相同,存储在栈上。

示例

fn main() {
    let arr: [i32; 5] = [1, 2, 3, 4, 5]; // 指定类型和长度
    let same: [i32; 3] = [0; 3]; // 初始化为 [0, 0, 0]
    println!("arr = {:?}", arr); // 使用调试格式输出
    println!("第一个元素: {}", arr[0]);
    println!("same = {:?}", same);
}

说明

  • 数组类型写为 [T; N]T 是元素类型,N 是长度。
  • 访问越界会引发编译期或运行时错误。
  • [x; N] 表示初始化 N 个值为 x 的数组。

注意

  • Rust 更常用动态数组 Vec<T>(在标准库中),数组适合固定长度场景。

3. 字符串类型

Rust 有两种主要字符串类型:&str(字符串切片)和 String(可变字符串)。

3.1 &str

  • 字符串切片,引用不可变的字符串数据。
  • 通常作为字符串字面量(如 "hello")。

示例

fn main() {
    let s: &str = "Hello, Rust!";
    println!("s = {}", s);
}

3.2 String

  • 可变、堆分配的字符串,拥有所有权。
  • 常用于动态字符串操作。

示例

fn main() {
    let mut s = String::from("Hello");
    s.push_str(", Rust!"); // 添加字符串
    println!("s = {}", s);
}

说明

  • &str 轻量且不可变,适合静态字符串。
  • String 可变,适合动态修改。
  • 两者可通过 &String 转换为 &str

4. 其他类型

4.1 枚举(Enum)

枚举定义一组相关值,详见前文“Rust 基础语法”中的枚举部分。

示例

enum Color {
    Red,
    Green,
    Blue(u8), // 带数据的变体
}

fn main() {
    let color = Color::Blue(255);
    match color {
        Color::Red => println!("红色"),
        Color::Green => println!("绿色"),
        Color::Blue(value) => println!("蓝色: {}", value),
    }
}

4.2 结构体(Struct)

结构体定义自定义数据类型,详见前文“Rust 基础语法”。

示例

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 0, y: 0 };
    println!("Point: ({}, {})", p.x, p.y);
}

4.3 切片(Slice)

切片是引用数据的一部分,常见于字符串和数组。

示例

fn main() {
    let arr = [1, 2, 3, 4, 5];
    let slice: &[i32] = &arr[1..3]; // 切片包含 arr[1] 和 arr[2]
    println!("slice = {:?}", slice); // 输出: [2, 3]

    let s = String::from("hello");
    let slice: &str = &s[0..2]; // 字符串切片
    println!("slice = {}", slice); // 输出: he
}

说明

  • 切片是引用,不拥有数据。
  • 范围语法 [start..end]end 不包含。

5. 类型转换

Rust 不支持隐式类型转换,必须显式转换。

5.1 使用 as 关键字

示例

fn main() {
    let x: i32 = 42;
    let y: f64 = x as f64; // 转换为浮点数
    println!("y = {}", y);
}

5.2 使用 intofrom

某些类型可以通过 FromInto trait 转换。

示例

fn main() {
    let s = String::from("hello"); // 从 &str 到 String
    let num: i32 = "42".parse().unwrap(); // 字符串解析为整数
    println!("s = {}, num = {}", s, num);
}

说明

  • parse 返回 Result,需用 unwrap 或妥善处理错误。
  • String::from 是常见的构造方法。

6. 注意事项

  1. 类型推断
  • Rust 编译器会根据上下文推断类型,但复杂情况需显式指定。
  1. 内存安全
  • 数组和字符串操作受所有权和借用规则约束,防止越界或非法访问。
  1. 性能
  • 标量类型和数组存储在栈上,性能高。
  • StringVec 存储在堆上,适合动态数据。
  1. Unicode 支持
  • char&str 支持 Unicode,处理中文等字符时需注意字节与字符的区别。
  1. 调试输出
  • 使用 {:?} 格式化需要类型实现 Debug trait,结构体和枚举需添加 #[derive(Debug)]

7. 总结

Rust 的数据类型分为:

  • 标量类型:整数(i32, u32 等)、浮点数(f32, f64)、布尔(bool)、字符(char)。
  • 复合类型:元组(())、数组([T; N])。
  • 字符串&str(不可变切片)、String(可变堆分配)。
  • 其他:枚举(enum)、结构体(struct)、切片(&[T], &str)。

通过这些类型,Rust 提供了灵活且安全的编程模型。如果需要更深入的讲解(如自定义类型、trait 关联类型或高级转换),请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注