Rust 开发岗位核心面试指南(2026 最新版)
本资料涵盖 Rust 后端开发面试的核心知识点,适用于校招/社招准备。
最后更新: 2026 年 3 月 19 日
📑 目录
第一部分 Rust 基础与所有权
1.1 Rust 语言特性
核心特性:
- 内存安全:无需垃圾回收,编译期保证
- 零成本抽象:高级特性无运行时开销
- 并发安全:所有权系统防止数据竞争
- 模式匹配:强大的
match表达式 - 类型推断:减少显式类型标注
与其他语言对比:
| 特性 | Rust | C++ | Go | Java |
|---|---|---|---|---|
| 内存安全 | 编译期保证 | 手动管理 | GC | GC |
| 性能 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| 学习曲线 | 陡峭 | 陡峭 | 平缓 | 平缓 |
| 并发安全 | 编译期保证 | 运行时保证 | 运行时保证 | 运行时保证 |
1.2 所有权系统(⭐⭐⭐⭐⭐)
三大规则
1. 每个值都有一个变量,该变量是其所有者
2. 一次只能有一个所有者
3. 当所有者离开作用域时,值将被丢弃(drop)
所有权转移(Move)
fn main() {
let s1 = String::from("hello");
let s2 = s1; // 所有权转移,s1 不再有效
// println!("{}", s1); // ❌ 编译错误:value borrowed here after move
println!("{}", s2); // ✅ 正确
}
// 栈上数据 vs 堆上数据
let x = 5;
let y = x; // ✅ 拷贝,i32 实现 Copy trait
let s1 = String::from("hello");
let s2 = s1; // 转移,String 不实现 Copy
Drop trait
struct MyResource {
data: Vec<u8>,
}
impl Drop for MyResource {
fn drop(&mut self) {
println!("资源被释放");
// 自定义清理逻辑
}
}
fn main() {
let resource = MyResource { data: vec![1, 2, 3] };
// 离开作用域时自动调用 drop
}
提前释放
fn main() {
let s = String::from("hello");
// 使用 s
drop(s); // 显式提前释放
// s 不能再使用
}
1.3 变量与可变性
// 默认不可变
let x = 5;
// x = 6; // ❌ 错误
// 可变变量
let mut y = 5;
y = 6; // ✅ 正确
// 常量(必须标注类型)
const MAX_POINTS: u32 = 100_000;
// shadowing(遮蔽)
let x = 5;
let x = x + 1; // ✅ 新变量,遮蔽旧变量
let x = x * 2; // x = 12
// shadowing vs mut
let mut s = String::from("hello");
s = String::from("world"); // 重新赋值
let s = String::from("hello");
let s = String::from("world"); // shadowing,类型可以不同
1.4 数据类型
标量类型
| 类型 | 说明 | 示例 |
|---|---|---|
i32, i64, u32, u64 | 整数 | let x: i32 = 42; |
f32, f64 | 浮点数 | let pi: f64 = 3.14; |
bool | 布尔值 | let t = true; |
char | Unicode 字符 | let c: char = 'A'; |
复合类型
// 元组(固定长度,不同类型)
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // 解构
let five_hundred = tup.0;
// 数组(固定长度,相同类型)
let arr: [i32; 5] = [1, 2, 3, 4, 5];
let first = arr[0];
let zeros = [0; 10]; // [0, 0, ..., 0]
结构体
// 普通结构体
struct User {
username: String,
email: String,
active: bool,
}
// 元组结构体
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
// 单元结构体(无字段)
struct AlwaysEqual;
// 方法实现
impl User {
fn new(username: String, email: String) -> Self {
User {
username,
email,
active: true,
}
}
fn is_active(&self) -> bool {
self.active
}
}
枚举与模式匹配
// 枚举定义
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
// 模式匹配
fn handle_message(msg: Message) {
match msg {
Message::Quit => println!("退出"),
Message::Move { x, y } => println!("移动到 ({}, {})", x, y),
Message::Write(text) => println!("消息:{}", text),
Message::ChangeColor(r, g, b) => println!("颜色 ({}, {}, {})", r, g, b),
}
}
// Option 枚举
enum Option<T> {
Some(T),
None,
}
let some_number: Option<i32> = Some(5);
let absent_number: Option<i32> = None;
// match 处理 Option
match some_number {
Some(n) => println!("数字:{}", n),
None => println!("无值"),
}
// if let 简化
if let Some(n) = some_number {
println!("数字:{}", n);
}
第二部分 借用与引用
2.1 引用基础(⭐⭐⭐⭐⭐)
// 不可变引用
fn main() {
let s = String::from("hello");
let len = calculate_length(&s); // &s 创建引用
println!("{}", s); // s 仍有效
}
fn calculate_length(s: &String) -> usize {
s.len()
}
// 可变引用
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // "hello, world"
}
fn change(s: &mut String) {
s.push_str(", world");
}
2.2 借用规则(⭐⭐⭐⭐⭐)
规则 1: 在任意给定时刻,你只能拥有以下之一:
- 一个可变引用
- 任意数量的不可变引用
规则 2: 引用必须始终有效(无悬垂引用)
规则示例
// ✅ 多个不可变引用
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} {}", r1, r2);
// ❌ 同时存在可变和不可变引用
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
let r3 = &mut s; // 错误!
println!("{} {} {}", r1, r2, r3);
// ✅ 作用域分离
let mut s = String::from("hello");
{
let r1 = &s;
let r2 = &s;
println!("{} {}", r1, r2);
} // r1, r2 作用域结束
let r3 = &mut s; // 正确
r3.push_str("!");
// ✅ 可变引用使用后不能再借用
let mut s = String::from("hello");
let r1 = &mut s;
r1.push_str(",");
// let r2 = &mut s; // 错误!r1 仍在使用
2.3 悬垂引用
// ❌ 错误:悬垂引用
// fn dangling_reference() -> &String {
// let s = String::from("hello");
// &s // s 离开作用域后被释放
// }
// ✅ 正确:返回所有权
fn no_dangle() -> String {
let s = String::from("hello");
s
}
2.4 切片(Slice)
// 字符串切片
let s = String::from("hello world");
let hello = &s[0..5]; // "hello"
let world = &s[6..11]; // "world"
let hello = &s[..5]; // 省略开头
let world = &s[6..]; // 省略结尾
let all = &s[..]; // 整个字符串
// 函数参数使用切片
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
// 数组切片
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..3]; // [2, 3]
第三部分 生命周期
3.1 生命周期基础(⭐⭐⭐⭐)
定义:生命周期是引用的有效作用域,确保引用在使用期间始终有效。
为什么需要生命周期
// ❌ 无法编译:编译器无法确定返回引用的生命周期
// fn longest(x: &str, y: &str) -> &str {
// if x.len() > y.len() {
// x
// } else {
// y
// }
// }
// ✅ 正确:显式标注生命周期
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
3.2 生命周期注解语法
// 基本语法
fn func<'a>(x: &'a str, y: &'a str) -> &'a str { ... }
// 多个生命周期参数
fn multi_lifetime<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
x // 返回与 x 相同生命周期的引用
}
// 结构体中的生命周期
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("注意:{}", announcement);
self.part // 生命周期省略
}
}
3.3 生命周期省略规则
三条规则:
规则 1: 每个引用参数获得独立的生命周期参数
规则 2: 如果只有一个输入生命周期,它被赋给所有输出生命周期
规则 3: 如果有 &self 或 &mut self,self 的生命周期被赋给所有输出生命周期
省略示例
// 应用规则 2
fn first_word(s: &str) -> &str {
// 实际是:fn first_word<'a>(s: &'a str) -> &'a str
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
// 应用规则 3
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
// 实际是:fn level(&'a self) -> i32
3
}
fn announce_and_return_part(&self, announcement: &str) -> &str {
// self: &'a self, announcement: &'b str
// 返回 &'a str(与 self 相同)
self.part
}
}
3.4 'static 生命周期
// 'static 表示引用在整个程序运行期间有效
let s: &'static str = "静态字符串";
// 字面量都是 'static
const GREETING: &'static str = "Hello!";
// 注意:'static 不表示值不能改变,只表示引用有效时间长
3.5 常见面试题
Q1: 以下代码能否编译?为什么?
fn main() {
let s1 = String::from("long string");
let s2 = String::from("short");
let result = longest(s1.as_str(), s2.as_str());
println!("{}", result);
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
答案: ✅ 可以编译。s1 和 s2 的生命周期相同(整个 main 函数),返回的引用有效。
Q2: 什么时候必须手动标注生命周期?
答案:
- 函数返回引用且多个参数是引用
- 结构体包含引用字段
- impl 块中方法返回引用且与 self 无关
第四部分 智能指针
4.1 Box(⭐⭐⭐⭐)
用途:堆上分配数据的所有权指针
// 基本使用
let b = Box::new(5);
println!("b = {}", b);
// 递归类型
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
// 已知大小类型
struct Node {
value: i32,
next: Box<Option<Node>>,
}
4.2 Rc(⭐⭐⭐⭐)
用途:引用计数,多所有者(单线程)
use std::rc::Rc;
// 基本使用
let a = Rc::new(String::from("Hello"));
let b = Rc::clone(&a); // 增加引用计数
let c = Rc::clone(&a);
println!("引用计数:{}", Rc::strong_count(&a)); // 3
// 树形结构
enum Tree {
Node(i32, Vec<Rc<Tree>>),
Leaf,
}
4.3 RefCell(⭐⭐⭐⭐)
用途:内部可变性,运行时借用检查
use std::cell::RefCell;
// 基本使用
let data = RefCell::new(5);
println!("data = {:?}", data.borrow());
*data.borrow_mut() = 10; // 可变借用
println!("data = {:?}", data.borrow());
// 组合使用:Rc<RefCell<T>>
use std::rc::Rc;
let shared = Rc::new(RefCell::new(vec![1, 2, 3]));
let a = Rc::clone(&shared);
let b = Rc::clone(&shared);
a.borrow_mut().push(4);
println!("{:?}", b.borrow()); // [1, 2, 3, 4]
4.4 智能指针对比
| 类型 | 所有权 | 可变性 | 检查时机 | 线程安全 |
|---|---|---|---|---|
| Box | 单一 | 可变/不可变 | 编译期 | ✓ |
| Rc | 多所有者 | 不可变 | 编译期 | ✗ |
| RefCell | 单一 | 内部可变 | 运行时 | ✗ |
| Arc | 多所有者 | 不可变 | 编译期 | ✓ |
| Mutex | 单一 | 内部可变 | 运行时 | ✓ |
4.5 组合模式
// Rc<RefCell<T>> - 多所有者 + 可变
use std::rc::Rc;
use std::cell::RefCell;
let shared = Rc::new(RefCell::new(5));
let a = Rc::clone(&shared);
let b = Rc::clone(&shared);
*shared.borrow_mut() = 10;
println!("a={}, b={}, shared={}", a.borrow(), b.borrow(), shared.borrow());
// Arc<Mutex<T>> - 多线程 + 可变
use std::sync::{Arc, Mutex};
let data = Arc::new(Mutex::new(5));
let mut handles = vec![];
for _ in 0..3 {
let data_clone = Arc::clone(&data);
handles.push(std::thread::spawn(move || {
let mut num = data_clone.lock().unwrap();
*num += 1;
}));
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *data.lock().unwrap());
第五部分 trait 与泛型
5.1 泛型基础(⭐⭐⭐)
// 泛型函数
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
// 泛型结构体
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 特定类型实现
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
// 多泛型参数
struct Pair<T, U> {
first: T,
second: U,
}
5.2 trait 定义与实现(⭐⭐⭐⭐⭐)
// trait 定义
pub trait Summary {
fn summarize(&self) -> String;
// 默认实现
fn summarize_author(&self) -> String {
String::from("(Read more...)")
}
}
// 实现 trait
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
// 使用默认实现
pub struct Tweet {
pub username: String,
pub content: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
5.3 trait bound
// 语法
fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
// 多 trait bound
fn notify<T: Summary + Display>(item: &T) { ... }
// where 子句(复杂场景)
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
42
}
// impl Trait 语法
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course"),
}
}
5.4 常用标准库 trait
// Display vs Debug
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Point")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
// Clone vs Copy
#[derive(Clone)]
struct MyData {
data: Vec<u8>,
}
#[derive(Copy, Clone)]
struct MyPoint {
x: i32,
y: i32,
}
// PartialEq vs Eq
#[derive(PartialEq)]
struct Partial {
value: f32,
}
#[derive(Eq, PartialEq)]
struct Equal {
value: i32,
}
// PartialOrd vs Ord
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct MyOrder {
priority: u32,
}
5.5 关联类型与泛型 trait
// 关联类型
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
// 实现
struct Counter {
count: u32,
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
// 泛型 trait
trait Container<T> {
fn contains(&self, item: &T) -> bool;
}
第六部分 错误处理
6.1 panic! 与 Result(⭐⭐⭐⭐)
// panic! - 不可恢复错误
fn main() {
panic!("crash and burn!");
}
// Result 枚举
enum Result<T, E> {
Ok(T),
Err(E),
}
// 使用 Result
use std::fs::File;
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("打开文件失败:{:?}", error),
};
// 传播错误
use std::io::{self, Read};
use std::fs::File;
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("username.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
// ? 操作符简化
fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("username.txt")?.read_to_string(&mut s)?;
Ok(s)
}
// 更简洁
fn read_username_from_file() -> Result<String, io::Error> {
std::fs::read_to_string("username.txt")
}
6.2 错误传播模式
// main 返回 Result
use std::error::Error;
use std::fs::File;
fn main() -> Result<(), Box<dyn Error>> {
let f = File::open("hello.txt")?;
Ok(())
}
// 自定义错误类型
use std::fmt;
use std::error::Error;
#[derive(Debug)]
enum MyError {
Io(std::io::Error),
Parse(std::num::ParseIntError),
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MyError::Io(e) => write!(f, "IO 错误:{}", e),
MyError::Parse(e) => write!(f, "解析错误:{}", e),
}
}
}
impl Error for MyError {}
impl From<std::io::Error> for MyError {
fn from(err: std::io::Error) -> MyError {
MyError::Io(err)
}
}
impl From<std::num::ParseIntError> for MyError {
fn from(err: std::num::ParseIntError) -> MyError {
MyError::Parse(err)
}
}
6.3 thiserror 与 anyhow
// thiserror - 库推荐
use thiserror::Error;
#[derive(Error, Debug)]
enum DataError {
#[error("数据未找到:{0}")]
NotFound(String),
#[error("网络请求失败")]
Request(#[from] reqwest::Error),
#[error("IO 错误")]
Io(#[from] std::io::Error),
}
// anyhow - 应用推荐
use anyhow::{Result, Context, bail};
fn read_config(path: &str) -> Result<String> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("无法读取配置文件:{}", path))?;
if content.is_empty() {
bail!("配置文件为空");
}
Ok(content)
}
第七部分 异步编程与 Tokio
7.1 Future 基础(⭐⭐⭐⭐⭐)
// Future trait
trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
enum Poll<T> {
Pending,
Ready(T),
}
// async/await 语法
async fn fetch_data() -> String {
// 异步操作
"data".to_string()
}
// async fn 返回的是 Future
fn returns_future() -> impl Future<Output = String> {
async { "data".to_string() }
}
7.2 Tokio 运行时(⭐⭐⭐⭐⭐)
use tokio;
// 多线程运行时(默认)
#[tokio::main]
async fn main() {
println!("Hello from Tokio!");
}
// 单线程运行时
#[tokio::main(flavor = "current_thread")]
async fn main() {
// 适合纯 I/O 密集型
}
// 手动创建运行时
use tokio::runtime::Runtime;
fn main() {
let rt = Runtime::new().unwrap();
rt.block_on(async {
println!("Hello!");
});
}
7.3 任务管理
// spawn 创建任务
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
println!("任务执行中");
42
});
let result = handle.await.unwrap();
println!("任务结果:{}", result);
}
// 并发执行多个任务
#[tokio::main]
async fn main() {
let task1 = tokio::spawn(async {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
"task1"
});
let task2 = tokio::spawn(async {
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
"task2"
});
let (r1, r2) = tokio::join!(task1, task2);
println!("{}, {}", r1.unwrap(), r2.unwrap());
}
// select 等待第一个完成
#[tokio::main]
async fn main() {
tokio::select! {
result = task1() => println!("task1 完成:{}", result),
result = task2() => println!("task2 完成:{}", result),
}
}
7.4 异步 I/O
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, addr) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = [0; 1024];
let n = socket.read(&mut buf).await.unwrap();
socket.write_all(&buf[..n]).await.unwrap();
});
}
}
7.5 同步原语
use tokio::sync::{Mutex, RwLock, mpsc, oneshot, Semaphore};
// Mutex
let m = Mutex::new(5);
{
let mut num = m.lock().await;
*num = 6;
}
// RwLock
let rw = RwLock::new(5);
{
let read = rw.read().await; // 多个读
}
{
let write = rw.write().await; // 独占写
*write = 10;
}
// mpsc channel(多生产者单消费者)
let (tx, mut rx) = mpsc::channel(32);
tokio::spawn(async move {
tx.send("hello").await.unwrap();
});
let msg = rx.recv().await.unwrap();
// oneshot channel(单次通信)
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
tx.send(42).unwrap();
});
let result = rx.await.unwrap();
// Semaphore(限流)
let sem = Semaphore::new(3);
let permit = sem.acquire().await.unwrap();
// 临界区
drop(permit); // 释放许可
7.6 超时与间隔
use tokio::time::{timeout, interval, sleep, Duration};
// 超时
match timeout(Duration::from_secs(5), async_op()).await {
Ok(result) => println!("完成:{}", result),
Err(_) => println!("超时"),
}
// 定时器
sleep(Duration::from_secs(1)).await;
// 间隔定时器
let mut int = interval(Duration::from_secs(1));
for _ in 0..5 {
int.tick().await;
println!("tick");
}
第八部分 并发编程
8.1 线程基础(⭐⭐⭐⭐)
use std::thread;
use std::time::Duration;
// 创建线程
let handle = thread::spawn(|| {
for i in 1..10 {
println!("子线程:{}", i);
thread::sleep(Duration::from_millis(1));
}
});
// 等待线程完成
handle.join().unwrap();
// 线程传值
let v = vec![1, 2, 3];
let handle = thread::spawn(move || { // move 转移所有权
println!("{:?}", v);
});
handle.join().unwrap();
8.2 消息传递
use std::sync::mpsc;
use std::thread;
// 通道
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("hello").unwrap();
});
let msg = rx.recv().unwrap(); // 阻塞接收
println!("收到:{}", msg);
// 多生产者
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();
thread::spawn(move || {
tx1.send("from tx1").unwrap();
});
thread::spawn(move || {
tx.send("from tx2").unwrap();
});
for received in rx {
println!("收到:{}", received);
}
8.3 共享状态
use std::sync::{Mutex, Arc};
use std::thread;
// Mutex
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;
}
// Arc + Mutex(多线程共享)
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("结果:{}", *counter.lock().unwrap());
8.4 Send 与 Sync trait
// Send: 可在线程间转移所有权
// Sync: 可在线程间共享引用(&T 是 Send)
// 自动实现:所有基本类型
// 不实现:Rc<T>(引用计数非原子)
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
fn main() {
assert_send::<i32>(); // ✅
assert_sync::<i32>(); // ✅
assert_send::<Rc<i32>>(); // ❌
assert_sync::<Rc<i32>>(); // ❌
assert_send::<Arc<i32>>(); // ✅
assert_sync::<Arc<i32>>(); // ✅
}
8.5 原子类型
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
let counter = Arc::new(AtomicUsize::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
counter.fetch_add(1, Ordering::SeqCst);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("结果:{}", counter.load(Ordering::SeqCst));
第九部分 内存管理与 unsafe
9.1 内存布局
栈(Stack) 堆(Heap)
┌─────────────┐ ┌─────────────┐
│ 局部变量 │ │ Box 数据 │
│ 函数参数 │ │ String 数据 │
│ 返回地址 │ │ Vec 数据 │
└─────────────┘ └─────────────┘
9.2 unsafe Rust
// unsafe 允许的操作:
// 1. 解引用裸指针
// 2. 调用 unsafe 函数
// 3. 访问可变静态变量
// 4. 实现 unsafe trait
// 裸指针
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
println!("r1: {}", *r1);
*r2 = 10;
}
// unsafe 函数
unsafe fn dangerous() {
// 不安全操作
}
unsafe {
dangerous();
}
// 调用外部代码
extern "C" {
fn abs(input: i32) -> i32;
}
unsafe {
println!("绝对值:{}", abs(-3));
}
9.3 内存泄漏
// 可能的泄漏
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum List {
Cons(i32, RefCell<Rc<List>>),
Nil,
}
// 循环引用导致泄漏
let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));
// 修复:使用 Weak
use std::rc::Weak;
let a = Rc::new(Cons(5, RefCell::new(Weak::new())));
9.4 Pin 与 Unpin
use std::pin::Pin;
use std::marker::Unpin;
// Pin 用于自引用结构
use std::pin::Pin;
struct SelfReferential {
data: String,
ptr: *const String,
}
// !Unpin 类型需要 Pin
let mut data = String::from("hello");
let pin = Pin::new(&mut data);
// async/await 生成的 Future 通常是 !Unpin
async fn foo() {}
let future = foo();
tokio::pin!(future); // 固定 Future
第十部分 高频面试题速查
10.1 Rust 基础
| 问题 | 关键词 |
|---|---|
| Rust 为什么不需要 GC? | 所有权系统、RAII |
| move 语义是什么? | 所有权转移、深拷贝 vs 浅拷贝 |
| Copy trait 作用? | 栈上拷贝、自动复制 |
| drop 如何工作? | Drop trait、作用域结束 |
| match 与 if let 区别? | 穷尽检查、简化语法 |
10.2 所有权与借用
| 问题 | 关键词 |
|---|---|
| 所有权三大规则 | 单一所有者、作用域释放 |
| 借用规则 | 可变/不可变互斥 |
| 什么是悬垂引用? | 引用无效、编译错误 |
| 切片的作用? | 引用连续内存、&str |
| &str vs String | 切片 vs 所有权、栈 vs 堆 |
10.3 生命周期
| 问题 | 关键词 |
|---|---|
| 生命周期作用 | 防止悬垂引用 |
| 生命周期省略规则 | 三条规则 |
| 'static 含义 | 程序整个运行期 |
| 何时需要标注生命周期? | 返回引用、多参数 |
10.4 智能指针
| 问题 | 关键词 |
|---|---|
| Box vs Rc vs Arc | 单所有者、多所有者、线程安全 |
| RefCell 作用 | 内部可变性、运行时检查 |
| Rc<RefCell> 场景 | 多所有者 + 可变 |
| Arc<Mutex> 场景 | 多线程 + 可变 |
| 内存泄漏如何产生? | 循环引用 |
10.5 trait 与泛型
| 问题 | 关键词 |
|---|---|
| trait 与接口区别 | 默认实现、关联类型 |
| trait bound 语法 | T: Trait、where |
| impl Trait 用法 | 返回类型、匿名类型 |
| dyn trait 是什么? | 动态分发、trait 对象 |
| Send vs Sync | 线程转移、线程共享 |
10.6 错误处理
| 问题 | 关键词 |
|---|---|
| panic! vs Result | 不可恢复、可恢复 |
| ? 操作符原理 | 错误传播、From trait |
| thiserror vs anyhow | 库、应用 |
| 自定义错误类型 | Error trait、From 实现 |
10.7 异步编程
| 问题 | 关键词 |
|---|---|
| Future 工作原理 | poll、状态机 |
| async/await 原理 | 状态机、挂起点 |
| Tokio 运行时架构 | 调度器、Reactor |
| spawn vs block_on | 任务创建、阻塞等待 |
| select! 宏作用 | 多 Future 竞争 |
10.8 并发编程
| 问题 | 关键词 |
|---|---|
| 线程创建方式 | thread::spawn、move |
| 消息传递 vs 共享状态 | channel、Mutex |
| Mutex vs Atomic | 锁、原子操作 |
| mpsc vs oneshot | 多生产者、单次 |
| 数据竞争如何防止? | 所有权、借用检查 |
附录 A. 复习优先级
第一梯队(必会):
✅ 所有权与借用规则
✅ 生命周期基础
✅ 智能指针(Box/Rc/Arc/Mutex)
✅ trait 与泛型
✅ 错误处理(Result/?)
✅ Tokio 异步基础
第二梯队(高频):
✅ 模式匹配
✅ 切片与字符串
✅ 并发编程
✅ unsafe 基础
第三梯队(加分):
✅ Pin/Unpin
✅ 自定义错误类型
✅ Tokio 高级特性
✅ 性能优化
附录 B. 推荐资源
- 官方文档: doc.rust-lang.org/book/
- Rust By Example: doc.rust-lang.org/rust-by-exa…
- Tokio 文档: tokio.rs
- Rust 面试题: www.mianshiya.com/bank/199143…