Rust

技术栈
后端框架
systemsmemory-safewasmcargotraits

概览

Rust 技术栈概览

Rust 是由 Mozilla Research 发起、现由 Rust 基金会维护的系统级编程语言。Graydon Hoare 于 2006 年开始设计,2015 年发布 1.0。它以「零成本抽象」「内存安全(无 GC)」「 fearless concurrency」三大原则著称,连续多年在 Stack Overflow 开发者调查中被评为「最受喜爱的语言」。

解决什么问题

  • C/C++ 的内存安全问题(悬垂指针、缓冲区溢出、use-after-free)→ 所有权+借用检查器编译期消除
  • 并发编程的数据竞争 → Send/Sync trait 编译期保证线程安全
  • 性能与控制力的矛盾 → 零成本抽象,高级语法生成与手写 C 等价的机器码
  • 包管理碎片化 → Cargo 统一构建/测试/文档/依赖管理

关键特性

  • 所有权系统(Ownership):每个值有唯一所有者,离开作用域自动释放
  • 借用检查器(Borrow Checker):编译期确保引用不会超过被引用值的生命周期
  • 模式匹配matchif letwhile let
  • Trait 系统:类似 Haskell typeclass 的多态机制
  • 枚举(Enum)与Option/Result:强制错误处理,没有 null
  • Cargo:内置包管理器 + 构建系统
  • 宏系统:声明宏 macro_rules! 和过程宏
  • WASM 支持:编译到 WebAssembly 的一等公民

安装

环境准备

  • OS:Linux / macOS / Windows(WSL2 推荐)
  • 编辑器推荐:VS Code + rust-analyzer 插件,或 JetBrains RustRover / CLion + Rust 插件
  • 依赖:系统需有 C 编译器(Linux: build-essential、macOS: Xcode Command Line Tools、Windows: Visual Studio Build Tools)

安装命令

官方推荐:rustup(版本管理 + 工具链)

# Linux / macOS
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# 安装后生效
source "$HOME/.cargo/env"

# 验证
rustc --version
cargo --version

Windows

# 下载 rustup-init.exe
# https://rustup.rs/
# 或使用 winget
winget install Rustlang.Rustup

更新

rustup update

切换工具链

rustup default stable       # 稳定版
rustup default nightly     # 夜版(最新特性)
rustup target add wasm32-unknown-unknown  # WASM 编译目标

常见安装问题

Q1: macOS 编译报 cc 找不到

运行 xcode-select --install 安装命令行工具。

Q2: Windows 编译报 link.exe 找不到

安装 Visual Studio Build Tools,勾选「C++ 生成工具」和「Windows SDK」。

Q3: cargo build 特别慢

首次编译慢(下载+编译所有依赖)。后续增量编译很快。可配置国内镜像:~/.cargo/config.toml 添加 [source.crates-io] 替换为 registry = "sparse+https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/"

Q4: rust-analyer 不工作

在项目根目录运行 cargo check 确保项目能编译。大型项目等 analyzer 索引完成。

示例

Rust 例程:所有权与借用初体验

目标

通过一个命令行程序展示 Rust 核心概念:所有权、借用、模式匹配、Result 错误处理。

完整代码

use std::fs;
use std::io::{self, Write};

/// 统计文件中的单词数
fn count_words(text: &str) -> usize {
    text.split_whitespace().count()
}

/// 统计文件中的行数
fn count_lines(text: &str) -> usize {
    text.lines().count()
}

/// 读取文件内容,返回 Result
fn read_file(path: &str) -> Result<String, io::Error> {
    fs::read_to_string(path)
}

/// 程序入口
fn main() {
    let args: Vec<String> = std::env::args().collect();

    // 模式匹配处理参数
    let path = match args.get(1) {
        Some(p) => p,
        None => {
            eprintln!("用法: cargo run -- <文件路径>");
            std::process::exit(1);
        }
    };

    // Result 错误处理
    let content = match read_file(path) {
        Ok(c) => c,
        Err(e) => {
            eprintln!("读取文件失败: {}", e);
            std::process::exit(1);
        }
    };

    // 借用:content 的所有权不转移,只是借用给函数
    let words = count_words(&content);  // & 不可变借用
    let lines = count_lines(&content);  // 可以同时多个不可变借用

    println!("文件: {}", path);
    println!("行数: {}", lines);
    println!("单词数: {}", words);

    // ── 所有权演示 ──
    let s1 = String::from("hello");
    let s2 = s1;                    // s1 所有权移动到 s2
    // println!("{}", s1);          // ❌ 编译错误!s1 已失效
    println!("s2 拥有: {}", s2);

    let s3 = s2.clone();            // 深拷贝
    println!("s2: {}, s3: {} (clone 后两者都有效)", s2, s3);

    // ── 借用演示 ──
    let mut data = String::from("Rust");
    let r1 = &data;                 // 不可变借用
    let r2 = &data;                 // 可以多个不可变借用
    println!("r1: {}, r2: {}", r1, r2);
    // r1、r2 最后一次使用后,可以可变借用
    let r3 = &mut data;             // 可变借用
    r3.push_str("acean");
    println!("修改后: {}", r3);
}

运行步骤

cargo new rust-demo &;& cd rust-demo
# 将上面代码写入 src/main.rs

echo "Hello Rust
Welcome to ownership world" >; test.txt

cargo run -- test.txt

预期输出

文件: test.txt
行数: 2
单词数: 8
s2 拥有: hello
s2: hello, s3: hello (clone 后两者都有效)
r1: Rust, r2: Rust
修改后: Rustacean

关键要点

概念 规则
所有权 每个值有且仅有一个所有者
移动 赋值/传参默认移动(非 Copy 类型)
借用 &T 不可变借用(可多个),&mut T 可变借用(唯一)
生命周期 引用不能比它指向的值活得更久

教程

Rust 系统编程入门教程

第一章:Rust 为什么与众不同

1.1 内存安全的三种路线对比

语言 策略 代价
C/C++ 手动管理 悬垂指针、内存泄漏、UB
Java/Go/Python GC 自动回收 运行时开销、暂停
Rust 编译期所有权+借用检查 无运行时开销,但学习曲线陡

1.2 所有权三大规则

  1. Rust 中每个值都有一个被称为**所有者(owner)**的变量
  2. 同一时间值有且仅有一个所有者
  3. 当所有者离开作用域,值被自动释放(drop 函数调用)

第二章:Cargo 项目结构

my-project/
├── Cargo.toml       # 依赖+元信息(类似 package.json)
├── Cargo.lock       # 精确依赖版本
├── src/
│   ├── main.rs      # 入口点(可执行文件)
│   └── lib.rs       # 库根
└── tests/           # 集成测试

常用命令:

cargo new my-app         # 创建项目
cargo build              # 编译
cargo build --release    # 优化编译
cargo run                # 编译+运行
cargo test               # 测试
cargo fmt                # 格式化代码
cargo clippy             # Lint 检查

第三章:核心类型

3.1 Option——没有 null

enum Option<T> {
    Some(T),
    None,
}

3.2 Result——强制错误处理

enum Result<T, E> {
    Ok(T),
    Err(E),
}

? 运算符:let f = File::open("a.txt")?; 等价于「Ok 则解包,Err 则早期返回」。

3.3 Vec 和 HashMap

let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);

let mut scores = HashMap::new();
scores.insert("Blue", 10);

第四章:Trait 系统

Trait 定义共享行为:

trait Summary {
    fn summarize(&self) -> String;
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{} - by {}", self.title, self.author)
    }
}

泛型约束:

fn notify<T: Summary>(item: &T) { ... }
// 或语法糖
fn notify(item: &impl Summary) { ... }

第五章:并发模型

Rust 的并发哲学:无畏并发(Fearless Concurrency)

  • Send trait:该类型可以安全地在线程间转移所有权
  • Sync trait:该类型可以通过引用在线程间共享
  • 数据竞争在编译期被检测
use std::thread;

let handle = thread::spawn(|| {
    println!("来自子线程");
});
handle.join().unwrap();

思考题

  1. 为什么 Rust 可以有「无 GC 的内存安全」?所有权系统与 GC 的根本区别是什么?
  2. String&str 的区别?什么时候用哪个?
  3. 什么是「生命周期省略规则」?编译器如何自动推断引用生命周期?
  4. Rust 的 trait 和 Java 的 interface 有什么本质不同?

参考资料

暂无参考文献