Rust 不用 GC 却能保证内存安全,核心武器是所有权系统和借用检查器。编译期检查内存访问合法性,运行时零开销,但理解门槛是主流语言中最高的。
三大所有权铁律
1)每个值有且仅有一个所有者;2)所有者离开作用域,值立即被 drop;3)同一值最多只能有一个可变引用,可变和不可变引用不能同时存在。几乎所有初学生命周期错误都是违背第3条。
use std::collections::HashMap;
#[derive(Debug, Clone)]
struct User { id: u32, username: String, profile: Option<Box<User>> }
struct UserCache<'a> {
users: HashMap<u32, User>,
last_accessed: Option<&'a User>,
}
impl<'a> UserCache<'a> {
fn new() -> Self { Self { users: HashMap::new(), last_accessed: None } }
fn insert(&mut self, user: User) { self.users.insert(user.id, user); }
fn get(&'a mut self, id: u32) -> Option<&'a User> {
if let Some(u) = self.users.get(&id) {
self.last_accessed = Some(u);
self.last_accessed
} else { None }
}
}
fn longest_str<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() >= y.len() { x } else { y } }
struct Parser<'s, 'b> where 's: 'b { source: &'s str, buffer: &'b mut [u8] }
impl<'s, 'b> Parser<'s, 'b> where 's: 'b {
fn new(source: &'s str, buffer: &'b mut [u8]) -> Self { Self { source, buffer } }
}
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1={s1}, s2={s2}");
let a = String::from("short"); let b = String::from("longest string wins");
println!("longest: {}", longest_str(&a, &b));
let mut cache = UserCache::new();
cache.insert(User { id: 1, username: "rosetta".into(), profile: None });
let u = cache.get(1);
println!("Got user: {:?}", u.map(|x| &x.username));
let mut buf = vec![0u8; 1024];
let p = Parser::new("input", buf.as_mut_slice());
println!("Parser source len: {}", p.source.len());
}
生命周期标注与约束
当函数/结构体中出现引用时,Rust 需要显式生命周期标注('a、'b)告知编译器引用有效期关系。's: 'b 表示 's 存活时间不短于 'b,常见于结构体自引用场景。
| 常见错误 | 本质 | 修复模式 |
|---|---|---|
| use of moved value | 所有权被转移 | .clone()/用&borrow |
| cannot borrow X mutable+immutable | 违反借用规则 | 缩小作用域/分块 |
| missing lifetime specifier | 编译器推不出 | 加'a关联输入输出 |
| lifetime may not live long enough | 引用先被释放 | 延长作用域/改用拥有所有权类型 |
最佳实践
写代码初期全用拥有所有权类型(String/Vec/Box),编译通过后再按需改为引用。不要过早纠结生命周期标注,让编译器给你驱动式修改建议。