Rust 所有权系统详解:告别内存安全焦虑
Nina Santos | 2026-08-26T23:03:41 | Security
通过丰富的代码示例,深入理解 Rust 所有权、借用、生命周期三大核心概念,以及常见编译错误的解决方法。
# Rust 所有权系统详解 ## 为什么需要所有权? C/C++ 手动管理内存容易出错(悬垂指针、双重释放、内存泄漏)。Java/Go 用 GC 解决,但有性能开销。Rust 通过编译期的所有权系统实现零成本内存安全。 ## 所有权规则 1. 每个值有且仅有一个所有者 2. 当所有者离开作用域时,值被自动释放 3. 赋值或传参会发生所有权转移(move) ```rust fn main() { let s1 = String::from("hello"); let s2 = s1; // s1 的所有权转移给 s2 // println!("{}", s1); // 编译错误!s1 已无效 println!("{}", s2); // 正确 } ``` ## 借用(Borrowing) 不想转移所有权时,使用引用: ```rust fn calculate_length(s: &String) -> usize { // 不可变借用 s.len() } fn append_world(s: &mut String) { // 可变借用 s.push_str(", world!"); } fn main() { let mut greeting = String::from("hello"); let len = calculate_length(&greeting); println!("长度: {}", len); append_world(&mut greeting); println!("{}", greeting); // "hello, world!" } ``` ## 借用规则 1. 同一时间,可以有多个不可变引用 OR 一个可变引用(二选一) 2. 引用必须始终有效(不能悬垂) ```rust fn main() { let mut data = vec![1, 2, 3]; let first = &data[0]; // 不可变借用 // data.push(4); // 编译错误!不能在不可变借用期间修改 println!("第一个元素: {}", first); data.push(4); // first 已不再使用,可以修改了 } ``` ## 生命周期(Lifetime) ```rust // 编译器需要知道返回的引用来自哪个参数 fn longest(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } fn main() { let result; let string1 = String::from("长字符串"); { let string2 = String::from("短"); result = longest(string1.as_str(), string2.as_str()); println!("最长的是: {}", result); // 正确 } // println!("{}", result); // 错误:string2 已被释放 } ``` ## 常见模式 ```rust // Clone:显式拷贝(有性能开销) let s1 = String::from("hello"); let s2 = s1.clone(); println!("{} {}", s1, s2); // 两者都有效 // Rc:引用计数(多个所有者) use std::rc::Rc; let shared = Rc::new(vec![1, 2, 3]); let a = Rc::clone(&shared); // 引用计数 +1 let b = Rc::clone(&shared); // 引用计数 +1 println!("引用计数: {}", Rc::strong_count(&shared)); // 3 ``` ## 总结 所有权系统是 Rust 的灵魂。初期会频繁与编译器"斗争",但一旦理解,就能写出既安全又高效的代码。