Skip to content

Rust 所有权

概述

所有权(Ownership)是 Rust 最独特和重要的特性,它让 Rust 能够保证内存安全而无需垃圾回收器。本章将深入学习所有权系统的工作原理和使用方法。

🎯 所有权基本概念

所有权规则

rust
// Rust 所有权的三个规则:
// 1. Rust 中的每一个值都有一个被称为其 owner(所有者)的变量
// 2. 值在任一时刻有且只有一个所有者
// 3. 当所有者(变量)离开作用域,这个值将被丢弃

fn ownership_rules() {
    // 规则 1:每个值都有一个所有者
    let s = String::from("hello"); // s 是 "hello" 的所有者
    
    // 规则 2:同一时刻只能有一个所有者
    let s2 = s; // 所有权从 s 转移到 s2
    
    // println!("{}", s); // 编译错误!s 不再有效
    println!("{}", s2); // 正常,s2 现在是所有者
    
} // 规则 3:s2 离开作用域,内存被释放

变量与数据的交互

移动(Move)

rust
fn move_semantics() {
    // 基本类型:复制
    let x = 5;
    let y = x; // x 被复制到 y,两者都有效
    println!("x: {}, y: {}", x, y);
    
    // 复杂类型:移动
    let s1 = String::from("hello");
    let s2 = s1; // s1 的所有权移动到 s2
    
    // println!("{}", s1); // 编译错误!s1 已失效
    println!("{}", s2);
    
    // 解释移动的原因
    // String 在栈上的结构:
    // name     value
    // ptr      -> 指向堆上数据的指针
    // len      -> 字符串长度
    // capacity -> 分配的容量
    
    // 如果 Rust 允许复制,会有两个指针指向同一块堆内存
    // 当两个变量离开作用域时,都会尝试释放内存,导致二次释放错误
}

克隆(Clone)

rust
fn clone_semantics() {
    let s1 = String::from("hello");
    let s2 = s1.clone(); // 深拷贝,创建新的堆数据
    
    println!("s1: {}, s2: {}", s1, s2); // 两者都有效
    
    // 克隆的成本
    let large_string = "a".repeat(1_000_000);
    let cloned = large_string.clone(); // 昂贵的操作
    println!("原始长度: {}, 克隆长度: {}", large_string.len(), cloned.len());
}

复制(Copy)

rust
fn copy_trait() {
    // 实现了 Copy trait 的类型会被复制而不是移动
    let x = 5;
    let y = x; // 复制,不是移动
    println!("x: {}, y: {}", x, y);
    
    // Copy 类型包括:
    // - 所有整数类型
    // - 布尔类型
    // - 浮点类型
    // - 字符类型
    // - 元组(如果所有元素都是 Copy 的)
    
    let tuple = (1, 2.0, 'a');
    let tuple_copy = tuple; // 复制
    println!("原始: {:?}, 复制: {:?}", tuple, tuple_copy);
    
    // 不能同时实现 Copy 和 Drop
    // 如果类型实现了 Drop trait,就不能实现 Copy trait
}

// 自定义类型的 Copy
#[derive(Copy, Clone, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn custom_copy() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1; // 复制,不是移动
    
    println!("p1: {:?}, p2: {:?}", p1, p2);
}

🔄 所有权与函数

传递值给函数

rust
fn ownership_and_functions() {
    let s = String::from("hello");
    takes_ownership(s); // s 的值移动到函数里
    // println!("{}", s); // 编译错误!s 不再有效
    
    let x = 5;
    makes_copy(x); // x 的值被复制到函数里
    println!("{}", x); // x 仍然有效
}

fn takes_ownership(some_string: String) { // some_string 进入作用域
    println!("{}", some_string);
} // some_string 移出作用域并被丢弃

fn makes_copy(some_integer: i32) { // some_integer 进入作用域
    println!("{}", some_integer);
} // some_integer 移出作用域,没有特殊操作

返回值与作用域

rust
fn return_values_and_scope() {
    let s1 = gives_ownership(); // 函数返回值转移给 s1
    
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2); // s2 被移动到函数中,返回值转移给 s3
    
    println!("s1: {}, s3: {}", s1, s3);
    // println!("{}", s2); // 编译错误!s2 已被移动
}

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    some_string // 返回,所有权移动到调用函数
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string // 返回,所有权移动到调用函数
}

复杂的所有权转移

rust
fn complex_ownership_transfer() {
    let mut data = vec![1, 2, 3, 4, 5];
    
    // 函数可以返回多个值
    let (data, length) = calculate_length_and_return(data);
    println!("数据: {:?}, 长度: {}", data, length);
    
    // 使用元组返回多个值
    let result = process_data(data);
    match result {
        Some((processed_data, summary)) => {
            println!("处理后数据: {:?}", processed_data);
            println!("摘要: {}", summary);
        }
        None => println!("处理失败"),
    }
}

fn calculate_length_and_return(vec: Vec<i32>) -> (Vec<i32>, usize) {
    let length = vec.len();
    (vec, length) // 返回元组,所有权转移
}

fn process_data(mut data: Vec<i32>) -> Option<(Vec<i32>, String)> {
    if data.is_empty() {
        return None;
    }
    
    // 修改数据
    for item in &mut data {
        *item *= 2;
    }
    
    let summary = format!("处理了 {} 个元素", data.len());
    Some((data, summary))
}

🏗️ 所有权与数据结构

结构体的所有权

rust
#[derive(Debug)]
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn struct_ownership() {
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    
    // 移动整个结构体
    let user2 = user1;
    // println!("{:?}", user1); // 编译错误!user1 已被移动
    println!("{:?}", user2);
    
    // 部分移动
    let user3 = User {
        email: String::from("another@example.com"),
        username: String::from("anotherusername"),
        active: true,
        sign_in_count: 1,
    };
    
    let email = user3.email; // 只移动 email 字段
    let username = user3.username; // 只移动 username 字段
    
    // println!("{:?}", user3); // 编译错误!部分字段已被移动
    // 但是可以访问未移动的字段
    println!("活跃状态: {}, 登录次数: {}", user3.active, user3.sign_in_count);
}

枚举的所有权

rust
#[derive(Debug)]
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn enum_ownership() {
    let msg1 = Message::Write(String::from("hello"));
    let msg2 = msg1; // 移动
    
    // println!("{:?}", msg1); // 编译错误
    println!("{:?}", msg2);
    
    // 匹配时的所有权转移
    match msg2 {
        Message::Write(text) => {
            println!("写入消息: {}", text);
            // text 的所有权在这里被获得
        }
        _ => {}
    }
    
    // println!("{:?}", msg2); // 编译错误!msg2 的内容已被移动
}

集合类型的所有权

rust
fn collection_ownership() {
    // Vec 的所有权
    let mut vec1 = vec![1, 2, 3];
    let vec2 = vec1; // 移动
    
    // println!("{:?}", vec1); // 编译错误
    
    // 从 Vec 中取出元素
    let mut vec3 = vec![String::from("hello"), String::from("world")];
    let first = vec3.remove(0); // 移动出第一个元素
    
    println!("取出的元素: {}", first);
    println!("剩余的 Vec: {:?}", vec3);
    
    // HashMap 的所有权
    use std::collections::HashMap;
    
    let mut map = HashMap::new();
    let key = String::from("favorite");
    let value = String::from("blue");
    
    map.insert(key, value); // key 和 value 的所有权转移到 map
    // println!("{} {}", key, value); // 编译错误
    
    // 取回所有权
    if let Some(color) = map.remove("favorite") {
        println!("最喜欢的颜色: {}", color);
    }
}

🔀 所有权模式

RAII 模式

rust
use std::fs::File;
use std::io::prelude::*;

fn raii_pattern() {
    // 资源获取即初始化(RAII)
    {
        let mut file = File::create("temp.txt").expect("创建文件失败");
        file.write_all(b"Hello, RAII!").expect("写入失败");
        
        // 文件在这里被自动关闭,因为 file 离开作用域
    }
    
    // 文件已经被关闭
    
    // 自定义 RAII 类型
    let _guard = ResourceGuard::new("重要资源");
    // guard 会在离开作用域时自动清理资源
}

struct ResourceGuard {
    name: String,
}

impl ResourceGuard {
    fn new(name: &str) -> Self {
        println!("获取资源: {}", name);
        Self {
            name: name.to_string(),
        }
    }
}

impl Drop for ResourceGuard {
    fn drop(&mut self) {
        println!("释放资源: {}", self.name);
    }
}

构建器模式与所有权

rust
#[derive(Debug)]
struct Config {
    host: String,
    port: u16,
    ssl: bool,
}

struct ConfigBuilder {
    host: Option<String>,
    port: Option<u16>,
    ssl: Option<bool>,
}

impl ConfigBuilder {
    fn new() -> Self {
        Self {
            host: None,
            port: None,
            ssl: None,
        }
    }
    
    // 消费 self,返回新的 self
    fn host(mut self, host: String) -> Self {
        self.host = Some(host);
        self
    }
    
    fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }
    
    fn ssl(mut self, ssl: bool) -> Self {
        self.ssl = Some(ssl);
        self
    }
    
    // 消费 self,返回最终产品
    fn build(self) -> Result<Config, String> {
        let host = self.host.ok_or("缺少主机名")?;
        let port = self.port.unwrap_or(80);
        let ssl = self.ssl.unwrap_or(false);
        
        Ok(Config { host, port, ssl })
    }
}

fn builder_pattern_ownership() {
    let config = ConfigBuilder::new()
        .host(String::from("localhost"))
        .port(8080)
        .ssl(true)
        .build()
        .expect("构建配置失败");
    
    println!("配置: {:?}", config);
}

⚡ 性能考虑

避免不必要的移动

rust
fn performance_considerations() {
    // 不好的例子:不必要的移动
    let data = vec![1, 2, 3, 4, 5];
    let result = process_vec_bad(data);
    // data 不能再使用
    
    // 更好的例子:使用引用
    let data = vec![1, 2, 3, 4, 5];
    let result = process_vec_good(&data);
    println!("原始数据仍可用: {:?}", data);
    println!("处理结果: {}", result);
    
    // 当需要修改时才移动
    let mut data = vec![1, 2, 3, 4, 5];
    modify_vec(&mut data);
    println!("修改后的数据: {:?}", data);
}

fn process_vec_bad(vec: Vec<i32>) -> i32 {
    vec.iter().sum() // 不需要拥有所有权,但却移动了
}

fn process_vec_good(vec: &[i32]) -> i32 {
    vec.iter().sum() // 只需要读取,使用引用
}

fn modify_vec(vec: &mut Vec<i32>) {
    vec.push(6); // 需要修改,使用可变引用
}

智能的所有权管理

rust
use std::rc::Rc;
use std::cell::RefCell;

fn smart_ownership() {
    // 使用 Rc 共享所有权
    let data = Rc::new(vec![1, 2, 3, 4, 5]);
    let data1 = Rc::clone(&data);
    let data2 = Rc::clone(&data);
    
    println!("引用计数: {}", Rc::strong_count(&data));
    
    // 内部可变性
    let shared_data = Rc::new(RefCell::new(vec![1, 2, 3]));
    
    {
        let mut data = shared_data.borrow_mut();
        data.push(4);
    }
    
    println!("共享数据: {:?}", shared_data.borrow());
}

📝 本章小结

通过本章学习,你应该掌握了:

所有权核心概念

  • ✅ 所有权的三个基本规则
  • ✅ 移动、克隆、复制的区别
  • ✅ 所有权与函数调用
  • ✅ 返回值的所有权转移

高级所有权模式

  • ✅ 结构体和枚举的所有权
  • ✅ 集合类型的所有权管理
  • ✅ RAII 资源管理模式
  • ✅ 构建器模式中的所有权

性能优化

  • ✅ 避免不必要的移动和克隆
  • ✅ 选择合适的参数传递方式
  • ✅ 智能指针的使用场景
  • ✅ 内存管理的最佳实践

最佳实践

  1. 优先使用引用而非移动
  2. 在需要时才进行克隆
  3. 利用 RAII 管理资源
  4. 设计 API 时考虑所有权

继续学习下一章 - Rust 引用与借用

本站内容仅供学习和研究使用。