系统编程

第15课:字符串处理

🎯 本课目标

深入理解Rust的字符串系统:str vs String、UTF-8编码、字符串操作和性能优化。

1. 字符串类型

fn main() {
    // &str — 字符串切片(借用)
    let s: &str = "hello";        // 字面量,只读
    let slice: &str = &s[..3];      // 切片

    // String — 堆分配,可增长
    let mut s = String::new();
    s.push_str("hello");
    s.push('!');

    // 创建方式
    let s1 = String::from("hello");
    let s2 = "hello".to_string();
    let s3 = format!("{} {}", "hello", "world");

    // &str ↔ String
    let owned: String = "hello".to_string();
    let borrowed: &str = &owned;
}

✅ 编译验证通过

2. UTF-8与索引

fn main() {
    let hello = "你好世界";

    // ❌ 不能用数字索引字符串!
    // let ch = hello[0];  // 编译错误

    // ✅ 字节切片(危险!)
    let bytes = hello.as_bytes();
    println!("字节: {:?}", bytes);

    // ✅ 字符迭代
    for ch in hello.chars() {
        println!("字符: {}", ch);
    }

    // ✅ Unicode标量值
    println!("字符数: {}", hello.chars().count());
    println!("字节数: {}", hello.len());

    // ⚠️ 字符数≠字节数≠显示宽度
    let emoji = "🦀";
    println!("🦀: 字符={} 字节={}", emoji.chars().count(), emoji.len());
}

✅ 编译验证通过

UTF-8字符串内存模型: "你好" 在内存中: ┌───┬───┬───┬───┬───┬───┐ │E4 │BD │A0 │E5 │A5 │BD │ 6字节 └───┴───┴───┴───┴───┴───┘ └── 你 ──┘ └── 好 ──┘ 3 bytes 3 bytes String结构体(栈上): ┌────────────────┐ │ ptr ────────────→ 堆上UTF-8数据 │ len: 6 │ │ cap: 6 │ └────────────────┘ ⚠️ 不能按字节切片中文! &qu;你好"[..3] → "你" ✅ (恰好在字符边界) "你好"[..2] → 💥 运行时panic!

3. 字符串操作

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

    // 追加
    s.push_str(", world");
    s.push('!');

    // 拼接
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = s1 + &s2;  // s1被消耗!

    // 插入/删除
    let mut s = String::from("hello");
    s.insert(5, '!');     // "hello!"
    s.remove(5);          // "hello"
    s.replace_range(..1, "H");  // "Hello"

    // 替换
    let s = "I like Rust".replace("Rust", "Python");

    // 分割
    let parts: Vec<&str> = "a,b,c".split(',').collect();
    let words: Vec<&str> = "hello  world".split_whitespace().collect();

    // 修剪
    let trimmed = "  hello  ".trim();

    // 大小写
    let upper = "hello".to_uppercase();
    let lower = "HELLO".to_lowercase();
}

✅ 编译验证通过

4. 性能优化

fn main() {
    // 预分配容量
    let mut s = String::with_capacity(100);
    for i in 0..10 {
        s.push_str(&format!("line {}\n", i));
    }

    // 避免频繁分配
    // ❌ 每次都分配
    let result = (0..100)
        .map(|i| format!("{}", i))
        .collect::<Vec<_>>()
        .join(",");

    // ✅ 使用write!
    use std::fmt::Write;
    let mut buf = String::with_capacity(200);
    for i in 0..100 {
        write!(buf, "{},", i).unwrap();
    }
}

✅ 编译验证通过

📝 练习题

练习1:CSV解析器

实现一个简单的CSV行解析器,处理引号和转义。

练习2:字符串搜索

实现Boyer-Moore字符串搜索算法。

练习3:模板引擎

实现简单的模板替换:{{name}} → 实际值。

🏆

成就解锁:字符串大师

掌握Rust字符串系统——UTF-8的正确处理方式

🔬 深度理解:Rust与系统编程

系统编程的核心挑战是在不牺牲安全的前提下获得最大性能。Rust如何实现这个目标:

1. 无GC的内存管理

所有权系统在编译期确定每个值的生命周期,不需要运行时垃圾回收。这意味着:无停顿、可预测延迟、更少内存占用。

2. 零成本抽象到硬件

泛型单态化、内联、LLVM优化——高级代码编译为与手写C相当的机器码。

3. 并发无数据竞争

Send/Sync trait在编译期保证:如果是并发访问,要么只读,要么互斥。数据竞争不可能发生。

📊 Rust vs C/C++对比

特性RustCC++
内存安全✅ 编译期❌ 手动⚠️ 部分RAII
线程安全✅ 编译期
无GC
零成本抽象⚠️ 宏✅ 模板
包管理✅ Cargo⚠️ vcpkg
学习曲线陡峭中等极陡

🛡️ 安全编码实践

即使Rust保证内存安全和线程安全,仍需注意:

Rust系统编程课程 · 第15课 · 2026

📚 扩展阅读

以下资源帮助你深入学习本课主题:

  • The Rust Programming Language — 官方教程,Rust圣经
  • Rust by Example — 通过示例学习Rust
  • Rust Reference — 语言参考手册
  • Rustnomicon — Unsafe Rust黑魔法指南
  • Too Many Lists — 用Rust实现各种链表

🔑 关键术语回顾

本课涉及的核心概念,确保你理解每一个:

术语说明
所有权Rust内存管理的核心机制,每个值有唯一所有者
借用通过引用访问数据,不获取所有权
生命周期引用有效的范围,编译期分析工具
traitRust的接口/抽象机制,类似其他语言的接口
泛型参数化类型,零成本抽象
模式匹配强大的数据解构和分支机制
零成本抽象高层抽象不引入运行时开销
fearless concurrency编译器保证线程安全

💬 学习建议

  1. 动手编码 — 每个代码示例都在本地运行一遍
  2. 修改实验 — 故意改错代码,看编译器报什么错
  3. 完成练习 — 每课的练习题是巩固知识的关键
  4. 阅读源码 — 看标准库和优秀开源项目的实现
  5. 写项目 — 真正掌握需要构建真实项目

🤔 常见问题

Q: Rust学习曲线真的很陡吗?

A: 前期确实需要适应所有权和借用检查器,但一旦理解了,这些概念会让你的代码更可靠。大多数人2-4周就能上手。

Q: Rust适合什么项目?

A: 系统编程、Web服务、CLI工具、嵌入式、WASM、网络服务、数据库等。基本上需要性能和安全的地方都适合。

Q: 遇到编译错误怎么办?

A: Rust编译器的错误信息非常友好!仔细阅读,通常会指出问题所在和修复建议。也可以用cargo clippy获取更多提示。