Rust 所有权系统详解

2026-06-22 · 6 阅读 · 245字
Rust

Rust 所有权系统详解

所有权规则

Rust 的所有权系统是其最独特的特性,它在编译期保证内存安全,无需垃圾回收器。三条核心规则:

  1. 每个值在 Rust 中都有一个所有者
  2. 同一时间只能有一个所有者
  3. 当所有者离开作用域时,值被自动释放

移动语义

当将一个值赋给另一个变量时,所有权会发生转移(move):

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

这与浅拷贝不同——Rust 会使源变量失效,避免双重释放。

借用与引用

通过引用,可以在不转移所有权的情况下访问值:

fn calculate_length(s: &String) -> usize {
    s.len()
} // s 离开作用域,但不释放值

let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("{}: {}", s1, len); // s1 仍然有效

可变引用

fn change(s: &mut String) {
    s.push_str(" world");
}

let mut s = String::from("hello");
change(&mut s);

限制:同一作用域内,对同一个值只能有一个可变引用,或者多个不可变引用。

let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;     // 允许多个不可变引用
let r3 = &mut s; // 编译错误!已有不可变引用

生命周期

生命周期确保引用不会超过被引用值的存活时间:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

'a 是一个生命周期参数,表示返回值的存活时间不会超过 xy 中较短的那个。

生命周期省略规则

编译器在某些情况下可以自动推导生命周期:

  1. 每个输入引用都有自己的生命周期
  2. 如果只有一个输入生命周期,它会赋给所有输出引用
  3. 如果是方法,&self 的生命周期赋给所有输出引用

Drop trait

当值离开作用域时,Drop trait 的 drop 方法被自动调用:

struct Custom {
    data: String,
}

impl Drop for Custom {
    fn drop(&mut self) {
        println!("Dropping: {}", self.data);
    }
}

智能指针

Box

用于堆上分配值,适合递归类型和 trait 对象:

enum List {
    Cons(i32, Box<List>),
    Nil,
}

Rc

引用计数智能指针,允许多个所有者共享只读数据:

use std::rc::Rc;
let a = Rc::new(5);
let b = Rc::clone(&a);
let c = Rc::clone(&a);

RefCell

提供内部可变性,运行时检查借用规则:

use std::cell::RefCell;
let data = RefCell::new(5);
*data.borrow_mut() += 1;

总结

所有权系统让 Rust 在不牺牲性能的前提下保证内存安全。理解所有权、借用和生命周期是掌握 Rust 的关键。