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 资源管理模式
- ✅ 构建器模式中的所有权
性能优化
- ✅ 避免不必要的移动和克隆
- ✅ 选择合适的参数传递方式
- ✅ 智能指针的使用场景
- ✅ 内存管理的最佳实践
最佳实践
- 优先使用引用而非移动
- 在需要时才进行克隆
- 利用 RAII 管理资源
- 设计 API 时考虑所有权
继续学习:下一章 - Rust 引用与借用