强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第01章:Rust 语言概述

第01章:Rust 语言概述

1.1 Rust 的历史

诞生背景

Rust 最初由 Mozilla 员工 Graydon Hoare 于 2006 年作为个人项目开发,旨在创建一门安全且高效的系统编程语言。Mozilla 于 2009 年正式赞助该项目,目标是为 Firefox 浏览器引擎 Servo 提供底层支持。

发展时间线

年份里程碑
2006Graydon Hoare 开始个人项目
2009Mozilla 正式赞助
2010项目首次公开
2012发布 0.1 版本,开始收集社区反馈
2015Rust 1.0 正式发布(5月15日),确立稳定性承诺
2018Rust 2018 Edition,引入异步基础语法
2021Rust 2021 Edition,改进闭包捕获和数组 IntoIterator
2024Rust 2024 Edition,进一步简化异步编程

命名由来

Rust 以一种名为 锈菌(Rust Fungus) 的真菌命名,这种生物具有强大的生存能力和多态性,寓意语言本身的韧性和灵活性。

注意: Rust 语言的名称大小写始终为 Rust(首字母大写),而非 RUST 或 rust。但在代码和命令行中使用小写 rustccargo 等。


1.2 设计哲学

Rust 的设计围绕三大核心原则:

安全性(Safety)

Rust 最显著的设计目标是在编译时保证内存安全,无需垃圾回收器(GC)。

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1 的所有权移动到 s2

    // println!("{}", s1); // ❌ 编译错误:s1 已失效
    println!("{}", s2);    // ✅ 正常使用
}

并发性(Concurrency)

Rust 的类型系统和所有权规则天然防止数据竞争(data race):

use std::thread;

fn main() {
    let mut data = vec![1, 2, 3];

    // 所有权移动到新线程
    let handle = thread::spawn(move || {
        data.push(4);
        println!("子线程: {:?}", data);
    });

    // println!("{:?}", data); // ❌ 编译错误:data 已移动
    handle.join().unwrap();
}

零成本抽象(Zero-Cost Abstractions)

Rust 的抽象不会在运行时产生额外开销。你不用的东西不需付出代价,你用的东西手写也不会更好。

fn main() {
    // 使用迭代器链(高级抽象)
    let sum: i32 = (1..=100)
        .filter(|x| x % 2 == 0)
        .map(|x| x * x)
        .sum();

    println!("1到100中偶数的平方和: {}", sum);
    // 编译器会将上述代码优化为与手写循环同样高效的机器码
}

与其他语言的哲学对比

特性C/C++Java/GoRust
内存管理手动GC所有权系统
空指针存在存在(null)不存在(Option)
数据竞争运行时暴露运行时暴露编译时阻止
抽象开销可能有有(GC 暂停)零成本
学习曲线陡峭平缓陡峭但值得

1.3 内存安全模型

所有权系统(Ownership)

Rust 通过三条简单的规则管理内存:

  1. 每个值有且仅有一个所有者(owner)
  2. 同一时间只能有一个所有者
  3. 当所有者离开作用域,值被自动释放
fn main() {
    {
        let s = String::from("hello"); // s 是有效所有者
        println!("{}", s);
    } // s 离开作用域,String 被自动释放(调用 drop)

    // println!("{}", s); // ❌ 编译错误:s 已不存在
}

借用规则(Borrowing Rules)

在任意时刻,满足以下其中一个条件:

  • 任意数量的不可变引用(&T
  • 有且仅有一个可变引用(&mut T

二者不能同时存在。

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

    let r1 = &s;     // ✅ 不可变引用
    let r2 = &s;     // ✅ 不可变引用
    println!("{} {}", r1, r2);
    // r1 和 r2 在此之后不再使用(NLL)

    let r3 = &mut s; // ✅ 可变引用(此时 r1、r2 已失效)
    r3.push_str(", world");
    println!("{}", r3);
}

与 C/C++ 内存安全问题的对比

常见漏洞C/C++Rust
空指针解引用运行时崩溃编译时阻止(无 null)
悬垂指针未定义行为编译时阻止(生命周期)
缓冲区溢出运行时漏洞运行时 panic(边界检查)
使用已释放内存未定义行为所有权系统阻止
数据竞争未定义行为编译时阻止(Send/Sync)
双重释放未定义行为编译时阻止

注意: Rust 的内存安全保证仅适用于 Safe Rustunsafe 块中仍然可能引入内存安全问题,但编译器会明确标记这些区域。


1.4 零成本抽象

编译器优化示例

Rust 编译器基于 LLVM 后端,能够将高级抽象优化为高效机器码:

// 情况 1: 使用迭代器
fn sum_squares_iterator(n: u64) -> u64 {
    (1..=n).map(|x| x * x).sum()
}

// 情况 2: 使用手写循环
fn sum_squares_loop(n: u64) -> u64 {
    let mut sum = 0u64;
    for x in 1..=n {
        sum += x * x;
    }
    sum
}

fn main() {
    let n = 1000;
    println!("迭代器: {}", sum_squares_iterator(n));
    println!("手写循环: {}", sum_squares_loop(n));
    // 两种方式生成的机器码几乎完全相同
}

泛型单态化(Monomorphization)

Rust 在编译时为每种具体类型生成专用代码:

// 泛型函数
fn max_value<T: PartialOrd>(a: T, b: T) -> T {
    if a >= b { a } else { b }
}

fn main() {
    // 编译器会生成两个版本:
    // max_value_i32(a: i32, b: i32) -> i32
    // max_value_f64(a: f64, b: f64) -> f64
    println!("{}", max_value(10, 20));
    println!("{}", max_value(3.14, 2.71));
}

注意: 单态化会增加编译后二进制文件的大小(代码膨胀),但运行时性能与手写具体类型版本相同。


1.5 适用场景

Rust 的强项领域

领域说明代表项目
系统编程操作系统、驱动、嵌入式Redox OS, Tock
Web 后端高性能 API 服务Actix-web, Axum, Rocket
WebAssembly浏览器高性能模块wasm-bindgen, Yew
CLI 工具命令行工具开发ripgrep, bat, fd
网络服务代理、负载均衡Tokio, Hyper, Tower
数据库存储引擎TiKV, SurrealDB
游戏开发游戏引擎Bevy, Amethyst
区块链智能合约、节点Solana, Polkadot
安全工具静态分析、漏洞扫描Cargo-audit

Rust 可能不是最佳选择的场景

场景原因替代方案
快速原型开发编译慢、学习曲线陡Python, Ruby
简单脚本权重过高Python, Bash
GUI 桌面应用生态仍在成熟中C# (WPF), Kotlin
大型企业应用开发效率较低Java, C#
数据科学库生态不足Python (NumPy/Pandas)

1.6 第一个 Rust 程序

让我们快速感受 Rust 的风格:

use std::collections::HashMap;

/// 分析文本中每个单词的出现次数
fn word_count(text: &str) -> HashMap<&str, usize> {
    let mut counts = HashMap::new();
    for word in text.split_whitespace() {
        // entry API:键不存在则插入默认值,返回可变引用
        let count = counts.entry(word).or_insert(0);
        *count += 1;
    }
    counts
}

fn main() {
    let text = "hello world hello rust hello world";
    let counts = word_count(text);

    println!("单词统计结果:");
    for (word, count) in &counts {
        println!("  \"{}\" 出现 {} 次", word, count);
    }
}

运行输出(顺序可能不同,HashMap 无序):

单词统计结果:
  "rust" 出现 1 次
  "hello" 出现 3 次
  "world" 出现 2 次

1.7 Rust 与同类语言对比

与 C++ 对比

方面C++Rust
内存安全手动管理,容易出错编译时保证
编译速度较慢(模板)较慢(借用检查+单态化)
运行时极快极快(可比肩)
ABI 稳定无统一标准无(需 FFI)
并发安全依赖程序员编译器强制

与 Go 对比

方面GoRust
学习曲线平缓陡峭
垃圾回收有(GC 暂停)无(零开销)
并发模型goroutine + channel线程 + async/await
编译速度极快较慢
二进制大小较大较小
适用场景微服务、云原生系统、性能敏感

1.8 学习建议

克服"与借用检查器斗争"

初学者最常遇到的困难是与编译器的借用检查器(borrow checker)“斗争”。以下是建议:

  1. 接受编译器是朋友: 每个编译错误都在阻止一个潜在 bug
  2. 先理解生命周期: 理解值的存活范围是关键
  3. 使用 Clone 暂时绕过: 学习阶段可以用 .clone() 消除借用问题,之后再优化
  4. 阅读错误信息: Rust 的错误信息质量极高,仔细阅读通常能找到解决方案
  5. 练习、练习、再练习: 通过 Rustlings 练习

推荐学习资源

资源类型适合人群
The Rust Book官方教程所有初学者
Rust By Example示例教程喜欢动手的人
Rustlings练习题巩固知识
Rust 语言圣经中文教程中文读者
Programming Rust (O’Reilly)书籍深入学习

1.9 业务场景示例:为何选择 Rust

场景:构建高并发 API 网关

use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Instant;

/// 请求计数器(线程安全,无需锁)
struct RequestCounter {
    total: AtomicU64,
    errors: AtomicU64,
    start_time: Instant,
}

impl RequestCounter {
    fn new() -> Self {
        Self {
            total: AtomicU64::new(0),
            errors: AtomicU64::new(0),
            start_time: Instant::now(),
        }
    }

    fn record_request(&self, is_error: bool) {
        self.total.fetch_add(1, Ordering::Relaxed);
        if is_error {
            self.errors.fetch_add(1, Ordering::Relaxed);
        }
    }

    fn report(&self) {
        let elapsed = self.start_time().elapsed().as_secs_f64();
        let total = self.total.load(Ordering::Relaxed);
        let errors = self.errors.load(Ordering::Relaxed);
        let qps = total as f64 / elapsed;

        println!("总请求数: {}", total);
        println!("错误数:   {}", errors);
        println!("QPS:      {:.2}", qps);
    }
}

fn main() {
    let counter = Arc::new(RequestCounter::new());

    // 模拟多线程并发请求
    let handles: Vec<_> = (0..10)
        .map(|_| {
            let counter = Arc::clone(&counter);
            std::thread::spawn(move || {
                for i in 0..1000 {
                    counter.record_request(i % 50 == 0); // 每50个请求一个错误
                }
            })
        })
        .collect();

    for handle in handles {
        handle.join().unwrap();
    }

    counter.report();
}

选择 Rust 的理由

  • 无 GC 暂停: 保证低延迟(P99 < 10ms)
  • 内存安全: 减少线上因内存问题导致的崩溃
  • 零成本抽象: 迭代器、泛型不牺牲性能
  • 并发安全: 编译时防止数据竞争
  • 小二进制: 适合容器化部署

1.10 本章小结

要点说明
Rust 历史2006 年由 Graydon Hoare 创立,2015 年 1.0 发布
设计哲学安全、并发、零成本抽象
内存安全通过所有权系统和借用规则在编译时保证
零成本抽象高级语法不牺牲运行时性能
适用场景系统编程、Web 后端、CLI、嵌入式等

扩展阅读

  1. Rust 官方博客 — 版本发布和技术文章
  2. This Week in Rust — 每周 Rust 生态动态
  3. Rust 核心团队架构 — Rust 治理结构
  4. Oxide and Friends Podcast — 深度技术讨论
  5. RustConf 演讲视频 — 年度会议录像