所有权概念 #

一、所有权概述 #

所有权是Rust最独特的特性,它让Rust无需垃圾回收器就能保证内存安全。

1.1 所有权规则 #

Rust的三条核心所有权规则:

  1. Rust中的每个值都有一个所有者
  2. 同一时刻只能有一个所有者
  3. 当所有者离开作用域,值将被丢弃
rust
fn main() {
    {
        let s = String::from("hello");  // s 进入作用域
        
        // 使用 s
        println!("{}", s);
    }  // s 离开作用域,内存被释放
    
    // println!("{}", s);  // 错误:s 已失效
}

二、栈与堆 #

2.1 栈数据 #

基本类型存储在栈上,大小固定:

rust
fn main() {
    let x = 5;
    let y = x;  // 复制值
    
    println!("x = {}, y = {}", x, y);  // 两者都有效
}

2.2 堆数据 #

String 等类型存储在堆上:

rust
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // 移动所有权
    
    // println!("{}", s1);  // 错误:s1 已失效
    println!("{}", s2);     // 正确
}

2.3 String 内部结构 #

text
String 结构:
┌─────────────┬─────────────┬─────────────┐
│ ptr         │ len         │ capacity    │
│ (指针)       │ (长度)      │ (容量)      │
└─────────────┴─────────────┴─────────────┘
      │
      ▼
┌───┬───┬───┬───┬───┐
│ h │ e │ l │ l │ o │  堆上的数据
└───┴───┴───┴───┴───┘

三、移动语义 #

3.1 移动 #

当值被赋给另一个变量时,所有权被转移:

rust
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // s1 的所有权移动到 s2
    
    // println!("{}", s1);  // 错误:value borrowed here after move
    println!("{}", s2);
}

3.2 函数传参 #

将值传递给函数也会转移所有权:

rust
fn main() {
    let s = String::from("hello");
    
    takes_ownership(s);  // s 的所有权移动到函数
    
    // println!("{}", s);  // 错误:s 已失效
}

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
}  // some_string 离开作用域,内存被释放

3.3 函数返回值 #

返回值也会转移所有权:

rust
fn main() {
    let s1 = gives_ownership();  // 函数将所有权移动给 s1
    
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2);  // s2 移动到函数,函数返回值移动给 s3
    
    println!("s1 = {}", s1);
    println!("s3 = {}", s3);
    // println!("s2 = {}", s2);  // 错误:s2 已失效
}

fn gives_ownership() -> String {
    String::from("yours")
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string
}

四、克隆 #

4.1 clone 方法 #

使用 clone 创建深拷贝:

rust
fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();  // 深拷贝
    
    println!("s1 = {}", s1);
    println!("s2 = {}", s2);  // 两者都有效
}

4.2 克隆的代价 #

克隆会复制堆上的数据,可能开销较大:

rust
fn main() {
    let s1 = String::from("hello");
    
    // 克隆前
    println!("克隆前: {}", s1);
    
    let s2 = s1.clone();
    
    // 克隆后两者都有效
    println!("s1: {}, s2: {}", s1, s2);
}

五、Copy trait #

5.1 Copy 类型 #

实现了 Copy trait 的类型在赋值时会复制而不是移动:

rust
fn main() {
    let x = 5;
    let y = x;  // 复制,不是移动
    
    println!("x = {}, y = {}", x, y);  // 两者都有效
}

5.2 哪些类型实现了 Copy #

  • 所有整数类型:i32, u32, i64
  • 浮点类型:f32, f64
  • 布尔类型:bool
  • 字符类型:char
  • 元组(如果所有元素都是 Copy 类型):(i32, i32)
  • 不可变引用:&T
rust
fn main() {
    // 整数
    let a: i32 = 5;
    let b = a;
    println!("a: {}, b: {}", a, b);
    
    // 浮点
    let c: f64 = 3.14;
    let d = c;
    println!("c: {}, d: {}", c, d);
    
    // 布尔
    let e: bool = true;
    let f = e;
    println!("e: {}, f: {}", e, f);
    
    // 元组
    let g = (1, 2, 3);
    let h = g;
    println!("g: {:?}, h: {:?}", g, h);
    
    // 不可变引用
    let s = String::from("hello");
    let r1 = &s;
    let r2 = r1;  // 复制引用
    println!("r1: {}, r2: {}", r1, r2);
}

5.3 不能 Copy 的情况 #

rust
fn main() {
    // String 没有 Copy
    let s1 = String::from("hello");
    // let s2 = s1;  // 移动
    // println!("{}", s1);  // 错误
    
    // 可变引用没有 Copy
    let mut s = String::from("hello");
    let r1 = &mut s;
    // let r2 = r1;  // 错误:可变引用不能 Copy
    println!("{}", r1);
}

六、所有权与函数 #

6.1 传入函数 #

rust
fn main() {
    let s = String::from("hello");
    
    print_string(s.clone());  // 克隆后传入
    println!("仍然有效: {}", s);
    
    print_string(s);  // 移动所有权
    // println!("{}", s);  // 错误:s 已失效
}

fn print_string(s: String) {
    println!("{}", s);
}

6.2 返回所有权 #

rust
fn main() {
    let s1 = String::from("hello");
    let s2 = take_and_return(s1);
    
    println!("s2 = {}", s2);
}

fn take_and_return(s: String) -> String {
    println!("收到: {}", s);
    s  // 返回所有权
}

6.3 多返回值 #

rust
fn main() {
    let s1 = String::from("hello");
    let (s2, len) = calculate_length(s1);
    
    println!("字符串 '{}' 的长度是 {}", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len();
    (s, length)
}

七、作用域与 Drop #

7.1 自动释放 #

当变量离开作用域时,Rust自动调用 drop 方法:

rust
struct CustomData {
    data: String,
}

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

fn main() {
    let c = CustomData { data: String::from("test") };
    println!("使用 CustomData");
}  // c 离开作用域,自动调用 drop

7.2 提前释放 #

使用 std::mem::drop 提前释放:

rust
fn main() {
    let s = String::from("hello");
    println!("{}", s);
    
    drop(s);  // 提前释放
    
    // println!("{}", s);  // 错误:s 已被释放
    println!("s 已被释放");
}

八、部分移动 #

8.1 解构时的部分移动 #

rust
fn main() {
    let tuple = (String::from("hello"), 5);
    
    let (s, n) = tuple;  // 解构
    
    // println!("{:?}", tuple);  // 错误:tuple.0 已移动
    
    println!("s = {}", s);
    println!("n = {}", n);  // n 是 Copy 类型,仍然有效
}

8.2 数组元素的部分移动 #

rust
fn main() {
    let arr = [String::from("a"), String::from("b")];
    
    let s = arr[0].clone();  // 克隆
    println!("arr[0] = {}, s = {}", arr[0], s);
    
    let s2 = arr[1];  // 移动
    // println!("arr[1] = {}", arr[1]);  // 错误
    println!("s2 = {}", s2);
}

九、所有权图解 #

9.1 移动语义 #

text
移动前:
s1 ──→ [ptr|len|cap]
           │
           ▼
       [h|e|l|l|o]

移动后:
s1 (无效)
s2 ──→ [ptr|len|cap]
           │
           ▼
       [h|e|l|l|o]

9.2 克隆语义 #

text
克隆前:
s1 ──→ [ptr|len|cap]
           │
           ▼
       [h|e|l|l|o]

克隆后:
s1 ──→ [ptr|len|cap]      s2 ──→ [ptr|len|cap]
           │                         │
           ▼                         ▼
       [h|e|l|l|o]               [h|e|l|l|o]

十、实践示例 #

10.1 字符串处理 #

rust
fn process_string(s: String) -> String {
    let mut result = s;
    result.push_str(" processed");
    result
}

fn main() {
    let s1 = String::from("hello");
    let s2 = process_string(s1);
    
    println!("处理结果: {}", s2);
}

10.2 结构体所有权 #

rust
struct User {
    username: String,
    email: String,
    active: bool,
}

fn main() {
    let user = User {
        username: String::from("alice"),
        email: String::from("alice@example.com"),
        active: true,
    };
    
    // username 和 email 的所有权属于 user
    println!("用户: {}, 邮箱: {}", user.username, user.email);
    
    // 移动 username
    let username = user.username;
    println!("用户名: {}", username);
    
    // println!("用户: {}", user.username);  // 错误:已移动
    
    // active 是 Copy 类型
    let active = user.active;
    println!("活跃状态: {} {}", active, user.active);
}

十一、总结 #

本章学习了:

  • 所有权的三条核心规则
  • 栈与堆的区别
  • 移动语义
  • 克隆与深拷贝
  • Copy trait
  • 函数与所有权
  • 作用域与 Drop

所有权是Rust内存安全的核心机制。下一章,我们将学习引用与借用。

最后更新:2026-03-27