
借用:数据还是你的,我只是"借来看看"
还记得所有权那篇讲的吗?Rust 里每个值只有一个所有者,所有权转移后原变量就不能用了。
但这样有个问题:如果我想临时用一下某个值,但不想拿走它的所有权,怎么办?
fn main() {
let s1 = String::from("hello");
let len = calculate_length(s1); // s1 的所有权被转移了
println!("{} 的长度是 {}", s1, len); // 错误!s1 已经不能用了
}
这时候就需要**借用(Borrowing)**了。借用就像你借朋友的书看:书还是朋友的,你只是临时看看,看完还回去。
今天咱们就来彻底搞懂 Rust 的借用和引用,这是 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 是引用
s.len()
}
关键点:
&String 表示"引用一个 String"s1 还能继续使用&mut默认引用是不可变的(不能修改)。想修改?用 &mut。
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // 输出:hello, world
}
fn change(s: &mut String) {
s.push_str(", world");
}
注意:
mut&mut TRust 的借用检查器有三条核心规则:
规则 1 详解:
let mut s = String::from("hello");
let r1 = &s; // ✅ 不可变引用
let r2 = &s; // ✅ 可以有多个不可变引用
let r3 = &mut s; // ❌ 错误!同时存在可变和不可变引用
let mut s = String::from("hello");
let r1 = &mut s; // ✅ 可变引用
let r2 = &mut s; // ❌ 错误!只能有一个可变引用
规则 2 详解:引用不能比它指向的数据活得久(后面详细讲)。
规则 3 详解:
let mut s = String::from("hello");
{
let r1 = &mut s;
r1.push_str(", world");
} // r1 在这里离开作用域
let r2 = &mut s; // ✅ 现在可以了,r1 已经"还回去"了
悬垂引用(Dangling Reference)是指引用指向的内存已经被释放。
fn dangle() -> &String {
let s = String::from("hello");
&s // 错误!s 在函数结束时被 drop 了
}
编译器错误:
error[E0106]: missing lifetime specifier
--> src/main.rs:1:16
|
1 | fn dangle() -> &String {
| ^ expected named lifetime parameter
人话翻译:编译器:"你返回的引用指向谁?s 在函数结束时就没了,你让引用指向空气吗?"
修复:返回所有权,而不是引用。
fn no_dangle() -> String {
let s = String::from("hello");
s // 返回所有权
}
切片(Slice)是对集合中连续范围的引用。
let s = String::from("hello world");
let hello = &s[..]; // "hello"
let world = &s[..]; // "world"
切片类型:
&str&[T]let arr = [, , , , ];
let slice = &arr[..]; // &[2, 3],类型是 &[i32]
重点:切片不拥有数据,它只是引用。
fn main() {
let s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
// r1 和 r2 离开作用域
// s 还能用!
println!("{}", s);
}
fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
let r3 = &mut s; // ❌ 错误
println!("{}, {}, and {}", r1, r2, r3);
}
编译器错误:
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
--> src/main.rs:6:14
|
4 | let r1 = &s;
| -- immutable borrow occurs here
5 | let r2 = &s;
| -- immutable borrow occurs here
6 | let r3 = &mut s;
| ^^^^^^ mutable borrow occurs here
7 |
8 | println!("{}, {}, and {}", r1, r2, r3);
| -- immutable borrows used here
人话翻译:编译器:"s 已经被 r1 和 r2 不可变借用了,你又想可变借用?不行!要么大家只读,要么你一个人写,不能同时!"
修复:让不可变引用先结束。
fn main() {
let mut s = String::from("hello");
{
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
} // r1 和 r2 在这里结束
let r3 = &mut s; // ✅ 现在可以了
println!("{}", r3);
}
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
r1.push_str(", world");
println!("{}", s); // ❌ 错误!r1 还在借用中
}
编译器错误:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> src/main.rs:7:20
|
5 | let r1 = &mut s;
| ------ mutable borrow occurs here
6 | r1.push_str(", world");
7 | println!("{}", s);
| ^ immutable borrow occurs here
8 | }
| - mutable borrow ends here
人话翻译:编译器:"r1 正在可变借用 s,你又想访问 s?万一 r1 还在改怎么办?等 r1 用完再说!"
修复:
fn main() {
let mut s = String::from("hello");
{
let r1 = &mut s;
r1.push_str(", world");
} // r1 结束
println!("{}", s); // ✅ 现在可以了
}
fn get_first_word(s: &String) -> &str {
let word = String::from("hello");
&word // ❌ 错误!word 在函数结束时被 drop
}
编译器错误:
error[E0515]: cannot return reference to local variable `word`
--> src/main.rs:3:5
|
3 | &word
| ^^^^^ returns a reference to data owned by the current function
人话翻译:编译器:"你返回的引用指向 word,但 word 是函数里的局部变量,函数结束就没了。你这是想让人家引用个寂寞?"
修复:返回切片(引用传入的字符串)。
fn get_first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i];
}
}
&s[..] // 返回整个字符串的切片
}
mutlet s = String::from("hello");
let r = &mut s; // 错误!s 不是 mut
修复:let mut s = ...
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s; // 错误!
修复:用完一个再借用下一个。
let mut s = String::from("hello");
{
let r1 = &mut s;
// 用 r1
}
let r2 = &mut s; // ✅
let s = String::from("hello");
let slice = &s[..]; // panic!
修复:确保索引在范围内。
let slice = &s[..s.len()]; // ✅
&String vs &strfn print_string(s: &String) {
println!("{}", s);
}
fn main() {
let s = String::from("hello");
print_string(&s); // ✅
let literal = "hello";
print_string(&literal); // ❌ 错误!&str != &String
}
修复:用 &str 更灵活。
fn print_string(s: &str) {
println!("{}", s);
}
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i];
}
}
&s[..]
}
fn main() {
let my_string = String::from("hello world");
let word = first_word(&my_string);
println!("第一个单词:{}", word);
let my_literal = "hello world";
let word = first_word(my_literal); // 也能用!
println!("第一个单词:{}", word);
}
fn double_all(nums: &mut [i32]) {
for num in nums.iter_mut() {
*num *= ;
}
}
fn main() {
let mut nums = [, , , , ];
double_all(&mut nums);
println!("{:?}", nums); // [2, 4, 6, 8, 10]
}
#[derive(Debug)]
struct User {
name: String,
age: u32,
}
fn greet(user: &User) {
println!("你好,{}!", user.name);
}
fn have_birthday(user: &mut User) {
user.age += ;
}
fn main() {
let mut user = User {
name: String::from("Alice"),
age: ,
};
greet(&user); // 借用
have_birthday(&mut user); // 可变借用
greet(&user); // 还能用!
println!("{:?}", user);
}

& 创建&mut,要么多个 &,不能同时&str 和 &[T] 最常用下篇预告:字符串在 Rust 里是个"坑货",String 和 &str 傻傻分不清?下一篇专门聊聊字符串,彻底搞懂这对"双胞胎"!