元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
所有权系统
所有权规则
借用与引用
Move语义
切片与所有权
▶
生命周期
生命周期基础
生命周期省略规则
结构体中的生命周期
高阶生命周期
▶
类型系统
Traits与泛型
类型推断机制
PhantomData与泛型约束
Newtype模式
▶
并发模型
线程与消息传递
共享状态并发
异步编程基础
Future与Executor
▶
内存管理
栈与堆内存布局
内存分配器原理
Box与智能指针
内存安全策略
▶
错误处理
Result与Option
错误传播机制
Panic与Abort
自定义错误类型
▶
宏系统
声明宏与过程宏
宏展开机制
卫生宏实现
元编程实践
▶
Unsafe Rust
Unsafe关键字解析
原始指针操作
FFI交互实践
安全抽象模式
发布时间:
2025-03-22 09:04
↑
☰
# 借用与引用 借用(Borrowing)和引用(Reference)是Rust所有权系统中的重要概念,它们允许我们在不转移所有权的情况下使用值。本文将详细介绍Rust的借用系统和引用类型。 ## 引用基础 ### 1. 引用语法 ```rust fn main() { let s1 = String::from("hello"); let len = calculate_length(&s1); // 创建s1的引用 println!("'{}' 的长度是 {}", s1, len); // s1仍然可用 } fn calculate_length(s: &String) -> usize { s.len() } // s离开作用域,但不会释放指向的数据 ``` ### 2. 引用规则 1. 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用 2. 引用必须总是有效的(没有悬垂引用) ## 不可变引用 ### 1. 基本用法 ```rust fn main() { let s = String::from("hello"); let r1 = &s; // 第一个不可变引用 let r2 = &s; // 第二个不可变引用 println!("{} and {}", r1, r2); // 可以同时使用多个不可变引用 } ``` ### 2. 作用域规则 ```rust fn main() { let mut s = String::from("hello"); let r1 = &s; // 不可变引用1 let r2 = &s; // 不可变引用2 println!("{} and {}", r1, r2); // r1和r2最后一次使用 let r3 = &mut s; // 可以创建可变引用,因为之前的不可变引用已经不再使用 println!("{}", r3); } ``` ## 可变引用 ### 1. 基本用法 ```rust fn main() { let mut s = String::from("hello"); change(&mut s); println!("{}", s); // 输出 "hello, world" } fn change(some_string: &mut String) { some_string.push_str(", world"); } ``` ### 2. 可变性限制 ```rust fn main() { let mut s = String::from("hello"); let r1 = &mut s; // let r2 = &mut s; // 错误:不能同时存在多个可变引用 r1.push_str(", world"); println!("{}", r1); } ``` ## 高级借用模式 ### 1. 内部可变性 ```rust use std::cell::RefCell; fn main() { let data = RefCell::new(5); // 可以同时存在多个不可变借用 let r1 = data.borrow(); let r2 = data.borrow(); println!("r1 = {}, r2 = {}", r1, r2); // 修改值需要可变借用 let mut r3 = data.borrow_mut(); *r3 += 1; println!("r3 = {}", r3); } ``` ### 2. 生命周期与借用 ```rust fn main() { let string1 = String::from("长字符串"); let result; { let string2 = String::from("短字符串"); result = longest(&string1, &string2); println!("{}", result); } // string2在这里离开作用域 } fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } ``` ## 最佳实践 ### 1. 引用还是克隆 ```rust fn main() { let large_data = vec![1, 2, 3, 4, 5]; // 使用引用:高效但需要管理生命周期 process_data(&large_data); // 使用克隆:简单但可能影响性能 let data_clone = large_data.clone(); process_owned_data(data_clone); } fn process_data(data: &Vec<i32>) { println!("处理引用数据: {:?}", data); } fn process_owned_data(data: Vec<i32>) { println!("处理所有权数据: {:?}", data); } ``` ### 2. 避免引用循环 ```rust use std::rc::{Rc, Weak}; use std::cell::RefCell; #[derive(Debug)] struct Node { next: Option<Rc<RefCell<Node>>>, parent: RefCell<Weak<RefCell<Node>>>, } fn main() { let node1 = Rc::new(RefCell::new(Node { next: None, parent: RefCell::new(Weak::new()), })); let node2 = Rc::new(RefCell::new(Node { next: Some(Rc::clone(&node1)), parent: RefCell::new(Weak::new()), })); // 使用Weak引用避免循环引用 *node1.borrow_mut().parent.borrow_mut() = Rc::downgrade(&node2); } ``` ## 注意事项 1. **借用检查规则**: - 同一作用域内不能同时存在可变和不可变引用 - 可变引用不能有多个 - 引用不能比它指向的数据存活更久 2. **性能考虑**: - 引用不会产生运行时开销 - 避免不必要的克隆 - 合理使用内部可变性 3. **调试技巧**: - 使用编译器错误信息 - 理解生命周期标注 - 检查借用规则冲突 ## 总结 Rust的借用和引用系统是其内存安全的重要保障: 1. 通过借用规则防止数据竞争 2. 引用提供了高效的数据访问方式 3. 编译时检查确保内存安全 4. 灵活的借用模式满足不同需求 深入理解借用和引用机制对于编写高效的Rust代码至关重要。通过合理运用这些特性,我们可以在保证安全性的同时实现高性能的程序。