Skip to content

实战总结

> 综合练习本章各类型知识,通过实战示例建立 Rust 类型系统的完整认知。

完整示例

示例 1:学生信息管理系统

rust
fn main() {
    // 使用元组存储学生信息
    type Student = (u32, String, u8, f64);  // (学号,姓名,年龄,成绩)

    let students: Vec<Student> = vec![
        (1, String::from("张三"), 20, 95.5),
        (2, String::from("李四"), 21, 87.0),
        (3, String::from("王五"), 19, 92.3),
    ];

    println!("╔════════════════════════════════════╗");
    println!("║           学生信息表                ║");
    println!("╠════════════════════════════════════╣");

    for (id, name, age, score) in &students {
        println!("║ 学号:{:04} │ {:6} │ {:2}岁 │ {:5.1} ║",
                 id, name, age, score);
    }

    println!("╚════════════════════════════════════╝");

    // 计算平均分
    let total: f64 = students.iter().map(|(_, _, _, score)| score).sum();
    let average = total / students.len() as f64;
    println!("平均分:{:.2}", average);
}
▶ Run

示例 2:温度数据分析

rust
fn main() {
    // 一周温度(摄氏度)
    let temperatures: [f64; 7] = [22.5, 25.0, 19.8, 23.1, 26.4, 28.0, 24.5];

    println!("本周温度分析");
    println!("{:=<40}", "");

    // 打印每天温度
    let days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
    for (day, temp) in days.iter().zip(temperatures.iter()) {
        println!("{}: {:.1}°C", day, temp);
    }

    // 统计
    let max = temperatures.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
    let min = temperatures.iter().cloned().fold(f64::INFINITY, f64::min);
    let sum: f64 = temperatures.iter().sum();
    let avg = sum / temperatures.len() as f64;

    println!("{:=<40}", "");
    println!("最高温度:{:.1}°C", max);
    println!("最低温度:{:.1}°C", min);
    println!("平均温度:{:.1}°C", avg);
    println!("温差:{:.1}°C", max - min);
}
▶ Run

示例 3:简单密码验证器

rust
fn main() {
    let passwords: Vec<&str> = vec![
        "123456",      // 太弱
        "Abc123!@#",   // 强
        "password",    // 太弱
        "MyP@ssw0rd",  // 强
        "abcdefgh",    // 太弱
    ];

    println!("密码强度检查");
    println!("{:-<40}", "");

    for pwd in &passwords {
        let strength = check_password(pwd);
        println!("{:12} → {}", pwd, strength);
    }
}

fn check_password(password: &str) -> &str {
    let mut score = 0;

    // 长度检查
    if password.len() >= 8 {
        score += 1;
    }
    if password.len() >= 12 {
        score += 1;
    }

    // 包含大写字母
    if password.chars().any(|c| c.is_uppercase()) {
        score += 1;
    }

    // 包含数字
    if password.chars().any(|c| c.is_numeric()) {
        score += 1;
    }

    // 包含特殊字符
    if password.chars().any(|c| !c.is_alphanumeric()) {
        score += 1;
    }

    match score {
        0..=2 => "弱",
        3..=4 => "中等",
        5 => "强",
        _ => "非常强",
    }
}
▶ Run

调试技巧

使用 dbg! 宏调试类型

rust
fn main() {
    let s = String::from("hello");

    // dbg! 可以打印表达式和值
    let doubled = dbg!(s.len() * 2);

    // 打印类型信息
    println!("类型:{:?}", std::any::type_name_of_val(&s));

    // 打印内存大小
    println!("String 大小:{} 字节", std::mem::size_of::<String>());
    println!("&str 大小:{} 字节", std::mem::size_of::<&str>());
    println!("char 大小:{} 字节", std::mem::size_of::<char>());
}
▶ Run

格式化输出类型

rust
fn main() {
    let num: i32 = 42;

    // {:?} - 调试格式
    println!("调试格式:{:?}", num);

    // {:#?} - 美化调试格式
    let vec = vec![1, 2, 3];
    println!("美化格式:{:#?}", vec);

    // {:p} - 打印指针地址
    let s = String::from("hello");
    println!("String 数据地址:{:p}", s.as_str());

    // {:b}, {:x}, {:o} - 二进制,十六进制,八进制
    println!("二进制:{:b}", num);
    println!("十六进制:{:x}", num);
    println!("八进制:{:o}", num);
}
▶ Run

常见错误

错误 1:类型不匹配

rust
fn main() {
    // ❌ 错误:300 超出 i8 范围
    // let x: i8 = 300;

    // ✅ 正确:使用更大的类型
    let x: i16 = 300;

    // ❌ 错误:类型不匹配
    // let y: i32 = x;  // i16 不能自动转 i32

    // ✅ 正确:显式转换
    let y: i32 = x as i32;
}
▶ Run

错误信息:

error[E0308]: mismatched types
 --> src/main.rs:3:18
  |
3 |     let x: i8 = 300;
  |            --   ^^^ expected `i8`, found integer
  |            |
  |            expected due to this

错误 2:整数溢出(调试模式 panic)

rust
fn main() {
    let x: u8 = 255;
    // ❌ 这会在调试模式下 panic
    // let y = x + 1;

    // ✅ 安全处理
    let y = x.checked_add(1).unwrap_or(0);
    println!("y = {}", y);
}
▶ Run

错误信息:

thread 'main' panicked at 'attempt to add with overflow'

错误 3:数组越界

rust
fn main() {
    let arr = [1, 2, 3];
    // ❌ 这会 panic
    // let x = arr[10];

    // ✅ 安全访问
    match arr.get(10) {
        Some(val) => println!("{}", val),
        None => println!("索引超出范围"),
    }
}
▶ Run

错误信息:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 10'

错误 4:混淆 String 和&str

rust
fn main() {
    let s1: String = String::from("hello");
    let s2: &str = "world";

    // ❌ 错误:类型不匹配
    // let combined: &str = &s1 + s2;  // String + &str 不能直接得到&str

    // ✅ 正确:得到 String
    let combined: String = s1 + &s2;
    println!("{}", combined);

    // 或者使用 format!
    let s3 = String::from("hello");
    let s4 = format!("{} {}", s3, "world");
    println!("{}", s4);
}
▶ Run

错误 5:试图索引 String

rust
fn main() {
    let s = String::from("你好");

    // ❌ 错误:不能通过索引访问 String 中的字符
    // let first = s[0];

    // ✅ 正确:使用 chars()
    let first = s.chars().next().unwrap();
    println!("第一个字符:{}", first);
}
▶ Run

错误信息:

error[E0277]: the type `str` cannot be indexed by `{integer}`
 --> src/main.rs:4:19
  |
4 |     let first = s[0];
  |                   ^^^ string indices are ranges of `usize`

练习

练习 1:类型转换

编写程序,完成以下转换:

  1. 将 u16 值 1000 转换为 u8
  2. 将 i32 值 42 转换为 f64
  3. 将字符'A'转换为其 Unicode 码点

练习 2:数组操作

创建一个包含 10 个整数的数组,实现:

  1. 计算所有元素的和
  2. 找出最大值和最小值
  3. 计算平均值

练习 3:字符串处理

编写函数,接受一个&str,返回:

  1. 单词数量(按空格分割)
  2. 字符数量
  3. 大写字母数量

练习 4:温度转换

实现温度转换器:

  1. 摄氏度转华氏度:F = C × 9/5 + 32
  2. 摄氏度转开尔文:K = C + 273.15

小结

本章我们详细学习了:

标量类型

类型说明默认示例
i32有符号 32 位整数42
u8无符号 8 位整数255
f6464 位浮点数3.14
bool布尔值true, false
charUnicode 字符'A', '中', '🦀'

复合类型

类型说明示例
元组固定长度,可不同类型(1, "hello", true)
数组固定长度,相同类型[1, 2, 3, 4, 5]

String vs &str

特性String&str
所有权拥有借用
可变性可变不可变
大小24 字节16 字节
创建String::from()字面量 "hello"
用途需要修改时函数参数、只读

关键要点

  1. Rust 默认整数是 i32,默认浮点数是 f64
  2. 类型转换用 as 关键字
  3. 数组越界会 panic,用 get() 安全访问
  4. String 是可增长的,&str 是切片/视图
  5. 不能通过索引访问 String 中的字符(因为 UTF-8 编码)

第 05 章:函数

练习题

详见:练习题