1305 字
4 分钟
为什么 Rust 有所有权系统
Rust 是近年来最受关注的编程语言之一,其核心创新——所有权系统(Ownership System)——让它在没有垃圾回收(GC)的情况下实现了内存安全。这个设计让很多开发者既好奇又困惑:为什么 Rust 要设计这样一套看似复杂的规则?
一、内存安全:程序员的永恒难题
1.1 内存安全的三大问题
在 Rust 出现之前,内存管理主要依赖两种方式:手动管理(C/C++)和垃圾回收(Java/Python)。这两种方式各有问题:
mindmap
root((内存安全问题))
悬垂指针
访问已释放内存
使用后释放 Use-After-Free
内存泄漏
忘记释放内存
循环引用
数据竞争
多线程并发访问
读写冲突
缓冲区溢出
数组越界访问
栈溢出攻击
这些问题导致的后果:
| 问题类型 | 后果 | 典型案例 |
|---|---|---|
| 悬垂指针 | 程序崩溃/安全漏洞 | Heartbleed 漏洞 |
| 内存泄漏 | 内存耗尽/性能下降 | 长时间运行的服务器 |
| 数据竞争 | 数据损坏/不可预测 | 多线程计数器错误 |
| 缓冲区溢出 | 安全漏洞/程序崩溃 | Morris 蠕虫、Code Red 蠕虫 |
1.2 传统解决方案的局限
flowchart TB
subgraph 手动管理
M1[C/C++] --> M2[完全控制]
M2 --> M3[高性能]
M2 --> M4[易出错]
M4 --> M5[安全隐患]
end
subgraph 垃圾回收
G1[Java/Python] --> G2[自动管理]
G2 --> G3[安全]
G2 --> G4[运行时开销]
G4 --> G5[GC 停顿]
end
subgraph 所有权系统
R1[Rust] --> R2[编译时检查]
R2 --> R3[零运行时开销]
R2 --> R4[内存安全]
end
style M5 fill:#f66
style G5 fill:#f96
style R3 fill:#6f6
style R4 fill:#6f6
手动管理的问题:
// C 语言中的典型错误void use_after_free() { int* ptr = malloc(sizeof(int)); *ptr = 42; free(ptr);
// 错误:访问已释放的内存 printf("%d\n", *ptr); // 悬垂指针!}
void memory_leak() { int* ptr = malloc(sizeof(int) * 1000); // 忘记 free(ptr) // 内存泄漏!}
void double_free() { int* ptr = malloc(sizeof(int)); free(ptr); free(ptr); // 双重释放!}垃圾回收的问题:
timeline
title GC 带来的运行时问题
程序运行 : 分配对象
: 对象可达
GC 触发 : 标记阶段
: 扫描所有可达对象
: 清除阶段
: 回收不可达对象
Stop-The-World : 所有线程暂停
: 用户感知卡顿
// Java 中的 GC 问题示例public class GCIssue { public static void main(String[] args) { // 大量临时对象创建 for (int i = 0; i < 1_000_000; i++) { String temp = new String("temporary " + i); // temp 很快变得不可达 // 但要等 GC 运行才会回收 } // GC 触发时可能导致明显停顿 }}1.3 Rust 的选择:第三条道路
Rust 的设计目标:
flowchart LR
A[设计目标] --> B[内存安全<br/>无 GC 开销]
A --> C[高性能<br/>零成本抽象]
A --> D[并发安全<br/>数据竞争自由]
B --> E[所有权系统]
C --> E
D --> E
E --> F[编译时保证]
style E fill:#f96
style F fill:#6f6
Rust 的核心洞见:
如果能在编译时通过静态分析确定内存的生命周期,就不需要运行时的垃圾回收。
二、所有权系统的三大规则
2.1 规则一:每个值有且只有一个所有者
flowchart TB
subgraph 所有权规则
R1["规则一:每个值有唯一的所有者"]
R2["规则二:同一时刻只能有一个所有者"]
R3["规则三:所有者离开作用域时值被释放"]
end
R1 --> E1[明确的生命周期]
R2 --> E2[避免重复释放]
R3 --> E3[自动内存释放]
E1 --> S[内存安全]
E2 --> S
E3 --> S
style S fill:#6f6
fn main() { // s 是字符串 "hello" 的所有者 let s = String::from("hello");
// s 离开作用域,内存自动释放}2.2 规则二:值可以被移动或借用
flowchart LR
A[值的使用方式] --> B[移动 Move]
A --> C[借用 Borrow]
B --> B1[所有权转移]
B1 --> B2[原变量失效]
C --> C1[临时使用]
C1 --> C2[所有权不变]
C --> D{借用类型}
D --> E[不可变借用 &T]
D --> F[可变借用 &mut T]
style B2 fill:#f96
style C2 fill:#6f6
移动语义:
fn main() { let s1 = String::from("hello"); let s2 = s1; // 所有权从 s1 移动到 s2
// println!("{}", s1); // 错误!s1 已失效 println!("{}", s2); // 正确}flowchart TB
subgraph 移动前
S1_1["s1"] --> P1["指针"] --> H1["堆: 'hello'"]
end
subgraph 移动后
S1_2["s1 (失效)"] -.->|无权访问| X[""]
S2["s2"] --> P2["指针"] --> H2["堆: 'hello'"]
end
style X fill:#f66
style S2 fill:#6f6
借用语义:
fn main() { let s1 = String::from("hello");
// 借用:s1 仍然拥有所有权 let len = calculate_length(&s1);
println!("'{}' 的长度是 {}", s1, len); // s1 仍然可用}
fn calculate_length(s: &String) -> usize { s.len() // s 是借用,离开作用域不会释放内存}2.3 规则三:借用规则
flowchart TB
A[借用规则] --> B[多个不可变借用]
A --> C[一个可变借用]
A --> D[不可变与可变互斥]
B --> B1["&T 可以同时存在多个"]
C --> C1["&mut T 同一时刻只能有一个"]
D --> D1["有 &mut T 时不能有 &T"]
D --> D2["有 &T 时不能有 &mut T"]
style B1 fill:#6f6
style C1 fill:#6f6
style D1 fill:#f96
style D2 fill:#f96
| 操作 | 代码示例 | 合法性 |
|---|---|---|
| 多个不可变借用 | let r1 = &s; let r2 = &s; | 合法 |
| 一个可变借用 | let r = &mut s; | 合法 |
| 可变 + 不可变 | let r1 = &s; let r2 = &mut s; | 非法 |
| 多个可变借用 | let r1 = &mut s; let r2 = &mut s; | 非法 |
fn main() { let mut s = String::from("hello");
// 多个不可变借用 let r1 = &s; let r2 = &s; println!("{} {}", r1, r2);
// 可变借用(之前的不可变借用已结束) let r3 = &mut s; r3.push_str(" world"); println!("{}", r3);
// 错误示例:同时存在可变和不可变借用 // let r4 = &s; // let r5 = &mut s; // println!("{} {}", r4, r5); // 编译错误!}三、借用检查器:编译时的守护者
3.1 借用检查器的工作原理
flowchart TB
A[源代码] --> B[词法分析]
B --> C[语法分析]
C --> D[类型检查]
D --> E[借用检查]
E --> F{检查通过?}
F -->|是| G[生成机器码]
F -->|否| H[编译错误]
subgraph 借用检查内容
E1[生命周期是否有效]
E2[借用规则是否遵守]
E3[数据竞争是否可能]
end
E --> E1
E --> E2
E --> E3
style G fill:#6f6
style H fill:#f66
借用检查器追踪什么:
fn main() { let r; // ---------+-- 'a // | { // | let x = 5; // -+-- 'b | r = &x; // | | } // -+ | // | println!("r: {}", r); // ---------+}编译错误:
error[E0597]: `x` does not live long enough --> src/main.rs:6:13 |6 | r = &x; | ^^ borrowed value does not live long enough7 | } | - `x` dropped here while still borrowed8 |9 | println!("r: {}", r); | - borrow later used here3.2 借用检查器如何防止错误
sequenceDiagram
participant Code as 源代码
participant BC as 借用检查器
participant Result as 检查结果
Code->>BC: 提交代码
BC->>BC: 分析变量生命周期
BC->>BC: 追踪借用关系
alt 借用合法
BC->>Result: 通过检查
Result->>Code: 编译成功
else 借用非法
BC->>Result: 发现问题
Result->>Code: 编译错误 + 详细提示
end
防止 Use-After-Free:
fn main() { let s = String::from("hello"); let ptr = &s;
drop(s); // 显式释放
// println!("{}", ptr); // 编译错误! // 借用检查器阻止了悬垂指针}防止数据竞争:
use std::thread;
fn main() { let mut data = vec![1, 2, 3];
let handle = thread::spawn(|| { // data.push(4); // 编译错误! // 无法捕获可变引用 });
data.push(5); // 主线程修改
handle.join().unwrap();}3.3 非词法作用域生命周期(NLL)
Rust 2018 引入了 NLL(Non-Lexical Lifetimes),使借用检查更智能:
flowchart TB
subgraph 词法作用域
L1["let r = &s;"] --> L2["// ..."]
L2 --> L3["// 使用 s"]
L3 --> L4["// r 作用域结束"]
end
subgraph NLL
N1["let r = &s;"] --> N2["// 最后使用 r"]
N2 --> N3["// 借用结束"]
N3 --> N4["// s 可再次借用"]
end
style L4 fill:#f96
style N3 fill:#6f6
fn main() { let mut s = String::from("hello");
let r = &s; println!("{}", r); // r 的最后一次使用
// NLL:借用已结束,可以再次可变借用 s.push_str(" world"); // 在 Rust 2018+ 中合法 println!("{}", s);}四、生命周期:明确的引用有效期
4.1 什么是生命周期?
flowchart TB
A[生命周期] --> B[引用的有效范围]
B --> C[确保引用始终有效]
A --> D[生命周期标注]
D --> E[帮助编译器推断]
E --> F[泛型生命周期参数]
style C fill:#6f6
生命周期是 Rust 独特的概念,用于追踪引用的有效范围:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y }}flowchart LR
subgraph 函数 longest
X["x: &'a str"] --> R["返回 &'a str"]
Y["y: &'a str"] --> R
end
subgraph 调用
S1["string1: 'a"] --> LONG["longest()"]
S2["string2: 'a"] --> LONG
LONG --> RES["结果: 'a"]
end
style R fill:#f96
style RES fill:#6f6
4.2 生命周期标注规则
mindmap
root((生命周期规则))
每个引用都有生命周期
编译器通常能推断
复杂情况需标注
生命周期标注语法
'a 表示泛型生命周期
可以有多个参数
省略规则
每个输入引用独立
只有一个输入时输出同生命周期
方法有 &self 时适用
三条省略规则:
// 规则示例
// 1. 每个输入引用独立fn foo(x: &i32, y: &i32); // 实际是 fn foo<'a, 'b>(x: &'a i32, y: &'b i32)
// 2. 只有一个输入,输出同生命周期fn foo(x: &str) -> &str; // 实际是 fn foo<'a>(x: &'a str) -> &'a str
// 3. 有 &self 时,输出借用 selfstruct Foo;impl Foo { fn bar(&self, x: &str) -> &str; // 输出借用 self}4.3 生命周期的实际应用
sequenceDiagram
participant Main as main()
participant Longest as longest()
participant Result as 返回值
Main->>Main: 创建 string1
Main->>Main: 创建 string2
Main->>Longest: 调用 longest(&string1, &string2)
Note over Longest: 比较长度
Longest->>Result: 返回较长的引用
Main->>Main: 使用 result
Note over Main: string1, string2 仍然有效
Main->>Result: 打印 result
fn main() { let string1 = String::from("long string");
{ let string2 = String::from("short"); let result = longest(string1.as_str(), string2.as_str()); println!("最长的是: {}", result); }
// println!("{}", result); // 错误!result 的生命周期已结束}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y }}4.4 结构体中的生命周期
// 结构体持有引用时必须标注生命周期struct ImportantExcerpt<'a> { part: &'a str,}
fn main() { let novel = String::from("Call me Ishmael. Some years ago..."); let first_sentence = novel.split('.').next().unwrap();
// first_sentence 借用 novel let excerpt = ImportantExcerpt { part: first_sentence, };
println!("{}", excerpt.part);
// excerpt 必须在 novel 之前离开作用域}五、与其他语言的对比
5.1 Rust vs C++ RAII
flowchart TB
subgraph C++ RAII
C1[资源获取即初始化]
C2[析构函数自动释放]
C3[依赖程序员习惯]
C4[可能忘记使用智能指针]
end
subgraph Rust 所有权
R1[所有权即资源管理]
R2[编译器强制检查]
R3[不可能忘记释放]
R4[不可能双重释放]
end
style C4 fill:#f96
style R3 fill:#6f6
style R4 fill:#6f6
C++ RAII 示例:
#include <memory>#include <iostream>
class Resource {public: Resource() { std::cout << "Acquired\n"; } ~Resource() { std::cout << "Released\n"; }};
void example() { // 正确使用智能指针 std::unique_ptr<Resource> ptr = std::make_unique<Resource>();
// 但这不是强制的! Resource* raw = new Resource(); // 可能忘记 delete // delete raw; // 忘记释放?
// 可能的问题 std::unique_ptr<Resource> ptr2 = std::move(ptr); // ptr->doSomething(); // 运行时错误,不是编译错误}Rust 所有权示例:
struct Resource;
impl Resource { fn new() -> Self { println!("Acquired"); Resource }}
impl Drop for Resource { fn drop(&mut self) { println!("Released"); }}
fn example() { let _r = Resource::new(); // 自动管理
// let r2 = r; // 移动后 r 失效 // println!("{:?}", r); // 编译错误!
// 不可能忘记释放 // 不可能双重释放}5.2 Rust vs Swift ARC
flowchart TB
subgraph Swift ARC
S1[自动引用计数]
S2[运行时开销]
S3[循环引用问题]
S4[weak/unowned 解决]
end
subgraph Rust 所有权
R1[编译时检查]
R2[零运行时开销]
R3[编译器检测循环]
R4[Rc/Arc 可选使用]
end
style S2 fill:#f96
style S3 fill:#f96
style R2 fill:#6f6
Swift ARC 示例:
class Person { var name: String var friend: Person? // 强引用,可能导致循环
init(name: String) { self.name = name print("\(name) created") }
deinit { print("\(name) deinitialized") }}
func createCycle() { let alice = Person(name: "Alice") let bob = Person(name: "Bob")
alice.friend = bob // alice -> bob bob.friend = alice // bob -> alice (循环引用!) // 内存泄漏!需要使用 weak var}Rust 所有权示例:
use std::rc::Rc;use std::cell::RefCell;
struct Person { name: String, friend: RefCell<Option<Rc<Person>>>,}
impl Drop for Person { fn drop(&mut self) { println!("{} released", self.name); }}
fn main() { let alice = Rc::new(Person { name: "Alice".to_string(), friend: RefCell::new(None), });
let bob = Rc::new(Person { name: "Bob".to_string(), friend: RefCell::new(None), });
// 循环引用会阻止释放 *alice.friend.borrow_mut() = Some(bob.clone()); *bob.friend.borrow_mut() = Some(alice.clone()); // 需要使用 Weak<T> 打破循环}5.3 三种方案对比
xychart-beta
title "内存管理方案对比"
x-axis ["安全性", "性能", "开发体验", "学习曲线"]
y-axis "评分" 0 --> 10
bar [4, 9, 6, 8]
bar [8, 6, 9, 9]
bar [10, 10, 5, 3]
| 特性 | C++ 手动/RAII | Swift ARC | Rust 所有权 |
|---|---|---|---|
| 内存安全 | 依赖程序员 | 运行时保证 | 编译时保证 |
| 运行时开销 | 无 | 引用计数开销 | 无 |
| 循环引用 | 需手动处理 | weak 引用 | Weak |
| 并发安全 | 不保证 | 不保证 | 编译时保证 |
| 学习曲线 | 中等 | 简单 | 陡峭 |
| 错误发现时机 | 运行时 | 运行时 | 编译时 |
六、所有权系统的代价与收益
6.1 学习曲线:最大的代价
flowchart LR
A[开始学习 Rust] --> B[所有权概念]
B --> C[借用规则]
C --> D[生命周期标注]
D --> E[智能指针]
B --> B1["困难度: "]
C --> C1["困难度: "]
D --> D1["困难度: "]
E --> E1["困难度: "]
style B fill:#f96
style D fill:#f96
常见的学习障碍:
// 障碍一:理解移动语义fn main() { let v = vec![1, 2, 3]; let v2 = v; // println!("{:?}", v); // 错误!v 已移动}
// 障碍二:生命周期标注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[..]}
// 障碍三:自引用结构struct SelfRef { value: String, pointer: *const String, // 原始指针绕过借用检查 // 或者使用 Pin<Box<T>>}6.2 编译器错误信息
Rust 编译器提供详细的错误信息:
fn main() { let s = String::from("hello"); let s1 = &s; let s2 = &mut s; println!("{} {}", s1, s2);}编译错误:
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable --> src/main.rs:4:14 |3 | let s1 = &s; | -- immutable borrow occurs here4 | let s2 = &mut s; | ^^^^^^ mutable borrow occurs here5 | println!("{} {}", s1, s2); | -- immutable borrow later used here6.3 收益:编译时保证的内存安全
flowchart TB
A[所有权系统] --> B[编译时检查]
B --> C[内存安全]
B --> D[并发安全]
B --> E[性能保证]
C --> C1[无悬垂指针]
C --> C2[无数据竞争]
C --> C3[无缓冲区溢出]
D --> D1[多线程安全]
D --> D2[Send/Sync trait]
E --> E1[零成本抽象]
E --> E2[无 GC 停顿]
E --> E3[可预测性能]
style C fill:#6f6
style D fill:#6f6
style E fill:#6f6
实际案例:
| 项目 | 使用 Rust 前后对比 |
|---|---|
| Firefox CSS 引擎 | 减少 50% 内存相关 bug |
| Dropbox 存储引擎 | 替代 C++,消除内存泄漏 |
| Cloudflare pingora | 比 Nginx 更快,无内存安全问题 |
| Discord 服务 | 性能提升,减少 GC 停顿 |
| AWS Firecracker | 安全的微虚拟机,内存隔离 |
6.4 性能对比
// Rust: 零成本抽象fn sum_rust(data: &[i32]) -> i32 { data.iter().sum() // 编译后与手写循环一样高效}
// Java: 有 GC 开销public int sumJava(int[] data) { int total = 0; for (int x : data) { total += x; } return total; // GC 可能在此期间运行}xychart-beta
title "内存管理开销对比"
x-axis ["分配", "访问", "释放", "GC 停顿"]
y-axis "相对开销" 0 --> 100
bar [10, 5, 8, 0]
bar [15, 10, 5, 40]
七、实战:所有权系统的应用
7.1 构建安全的字符串处理
fn process_string(input: &str) -> String { let mut result = String::new(); for word in input.split_whitespace() { if word.len() > 3 { result.push_str(word); result.push(' '); } } result.trim_end().to_string()}
fn main() { let original = String::from("hello world from rust");
// 借用 original,不获取所有权 let processed = process_string(&original);
println!("原始: {}", original); // original 仍然可用 println!("处理后: {}", processed);}7.2 安全的并发编程
use std::sync::{Arc, Mutex};use std::thread;
fn main() { // 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());}flowchart TB
subgraph 线程安全机制
A[Arc<T>] --> A1[原子引用计数]
A1 --> A2[多线程共享所有权]
M[Mutex<T>] --> M1[互斥访问]
M1 --> M2[同一时刻一个线程访问]
end
A --> S[安全的多线程编程]
M --> S
style S fill:#6f6
7.3 构建安全的数据结构
// 简单的链表节点pub struct List<T> { head: Link<T>,}
type Link<T> = Option<Box<Node<T>>>;
struct Node<T> { elem: T, next: Link<T>,}
impl<T> List<T> { pub fn new() -> Self { List { head: None } }
pub fn push(&mut self, elem: T) { let new_node = Box::new(Node { elem, next: self.head.take(), }); self.head = Some(new_node); }
pub fn pop(&mut self) -> Option<T> { self.head.take().map(|node| { self.head = node.next; node.elem }) }}八、智能指针:所有权的扩展
8.1 智能指针类型
mindmap
root((智能指针))
Box<T>
堆分配
单一所有权
已知大小
Rc<T>
引用计数
多重所有权
单线程
Arc<T>
原子引用计数
多重所有权
多线程安全
RefCell<T>
内部可变性
运行时借用检查
Mutex<T>
互斥锁
内部可变性
多线程安全
8.2 Box:堆分配
fn main() { // 在堆上分配 let b = Box::new(5); println!("b = {}", b);
// 递归类型 #[derive(Debug)] enum List<T> { Cons(T, Box<List<T>>), Nil, }
let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); println!("{:?}", list);}8.3 Rc:引用计数
use std::rc::Rc;
fn main() { let a = Rc::new(5); let b = Rc::clone(&a); // 引用计数 +1 let c = Rc::clone(&a); // 引用计数 +1
println!("引用计数: {}", Rc::strong_count(&a)); // 3}8.4 RefCell:内部可变性
use std::cell::RefCell;
fn main() { let x = RefCell::new(5);
{ let mut mutable = x.borrow_mut(); *mutable += 1; }
println!("{}", x.borrow()); // 6}九、所有权系统的设计哲学
9.1 权限与责任
flowchart TB
A[所有权哲学] --> B[权限]
A --> C[责任]
B --> B1[读取权限 &T]
B --> B2[写入权限 &mut T]
B --> B3[所有权转移]
C --> C1[确保引用有效]
C --> C2[避免数据竞争]
C --> C3[正确管理资源]
B1 --> D[编译器强制]
B2 --> D
C1 --> D
C2 --> D
style D fill:#6f6
9.2 零成本抽象原则
“What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better.”
— Bjarne Stroustrup
Rust 的所有权系统完美体现了这一原则:
// 高级抽象let sum: i32 = (1..=100).sum();
// 编译后与手写循环一样高效// 没有额外的运行时开销9.3 类型系统的力量
flowchart TB
A[类型系统] --> B[编译时检查]
B --> C[所有权规则]
B --> D[生命周期检查]
B --> E[类型安全]
C --> F[内存安全]
D --> F
E --> F
F --> G[运行时零开销]
style F fill:#6f6
style G fill:#6f6
十、总结与展望
10.1 所有权系统的核心价值
mindmap
root((所有权系统))
内存安全
无悬垂指针
无双重释放
无数据竞争
性能保证
零运行时开销
无 GC 停顿
可预测性能
并发安全
编译时检查
Send/Sync trait
无畏并发
工程价值
早期错误发现
明确的所有权语义
文档化资源管理
10.2 适用场景
| 场景 | 是否适合 Rust | 原因 |
|---|---|---|
| 系统编程 | 非常适合 | 内存安全 + 高性能 |
| 嵌入式开发 | 非常适合 | 零运行时,内存可预测 |
| Web 服务 | 适合 | 高并发,无 GC 停顿 |
| 命令行工具 | 适合 | 性能好,开发效率高 |
| WebAssembly | 非常适合 | 小体积,无运行时 |
| 快速原型开发 | 可能较慢 | 学习曲线陡峭 |
| 简单脚本 | 可能过重 | 编译时间,复杂度 |
10.3 学习建议
flowchart TD
A[学习 Rust] --> B[基础语法]
B --> C[所有权概念]
C --> D[借用与生命周期]
D --> E[实践项目]
C --> C1["重点理解:
- 每个值只有一个所有者
- 借用规则
- 移动 vs 复制"]
D --> D1["难点突破:
- 生命周期标注
- 智能指针选择
- 错误信息解读"]
E --> E1["推荐项目:
- 命令行工具
- Web 服务
- 系统工具"]
style C fill:#f96
style D fill:#f96
style E fill:#6f6
10.4 未来展望
timeline
title Rust 所有权系统演进
2010 : Rust 项目启动
: 所有权概念诞生
2012 : 借用检查器成熟
2015 : Rust 1.0 发布
: 稳定的所有权系统
2018 : NLL 引入
: 借用检查更智能
2021 : Rust 基金会成立
: 广泛采用
2024 : 异步 Rust 成熟
: 所有权 + async
未来 : 更好的错误信息
: 更低的学习曲线
: 更广泛的采用
参考资料
- The Rust Programming Language — Rust 官方教程
- Rust Ownership Explained — 所有权详解
- Fearless Concurrency with Rust — 无畏并发
- Rust内存安全研究 — Android 中的内存安全
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时
相关文章 智能推荐
1
为什么分布式系统有 CAP 定理
技术科普 深入理解 CAP 定理的本质,掌握分布式系统设计中一致性、可用性、分区容错性的权衡策略。
2
为什么 PostgreSQL 使用 MVCC
技术科普 深入解析多版本并发控制的设计原理,理解 PostgreSQL 如何实现高并发事务处理。
3
为什么系统调用会消耗较多资源
技术科普 深入解析系统调用的开销,为什么用户态切换到内核态需要消耗较多资源,以及如何优化。
4
为什么 WebSocket 需要握手
技术科普 深入解析 WebSocket 握手协议的设计原理,理解从 HTTP 到 WebSocket 的协议升级机制。
5
为什么 Docker 使用分层镜像
技术科普 深入解析 Docker 镜像分层设计的原理,理解 UnionFS、OverlayFS 如何实现高效的镜像存储与分发。






