& 的各种用法

不可变引用(借用)

最基本的形式,用于借用所有权而不转移:

1
2
3
4
5
6
7
fn print_length(s: &String) {
println!("{}", s.len());
} // s 在这里归还,不影响原数据

let s = String::from("hello");
print_length(&s);
println!("{}", s); // 还能用

可变引用 &mut

需要修改借用内容时使用,同一时间只能有一个可变引用

1
2
3
4
5
6
fn append(s: &mut String) {
s.push_str(" world");
}

let mut s = String::from("hello");
append(&mut s);

解引用 *

引用存的是地址,* 取值:

1
2
3
let x = 5;
let r = &x;
assert_eq!(*r, 5); // 解引用得到值

自动解引用

Rust 会隐式解引用,让代码简洁:

1
2
3
4
let s = String::from("hello");
let r = &s;
// 等价于 (*r).len()
let len = r.len();

模式匹配中的引用

不想转移所有权时:

1
2
3
4
5
6
let v = vec![1, 2, 3];
// 不获取所有权,只借用
for &x in &v {
println!("{}", x);
}
// v 还能用

for 循环中 & 的智能匹配

Rust 的 for 循环会自动尝试解引用,这是写法的对比:

1
2
3
4
5
6
7
8
9
10
11
let v = vec![1, 2, 3];

// 方式1: item 是 &i32
for item in &v {
println!("{}", *item); // 需要显式解引用
}

// 方式2: 使用 &x 模式,直接得到 i32
for &x in &v {
println!("{}", x); // x 已经是 i32
}

对于可变引用:

1
2
3
4
5
6
7
8
9
10
11
12
let mut v = vec![1, 2, 3];

// 修改元素
for x in &mut v {
*x *= 2; // 必须显式解引用才能修改
}

// 或者用 &mut 模式解构
for &mut x in &mut v {
x *= 2; // x 是 i32,但不能这样修改原值!
}
// 注意:&mut x 解构后得到的 x 是副本,修改不影响原数组

.iter() vs & 的区别:

1
2
3
4
5
6
7
// 这两者是等价的
for x in v.iter() // 显式调用 iter()
for x in &v // 隐式调用 iter()

// 这两者也等价
for x in v.iter_mut()
for x in &mut v

字面量前加 &

直接在字面量前加 & 创建引用,无需先绑定变量:

1
2
3
4
5
6
7
8
// 引用整数
let r: &i32 = &42;

// 引用字符串字面量
let s: &&str = &"hello";

// 引用数组
let arr: &[i32; 3] = &[1, 2, 3];

实用场景:函数参数期望引用时直接传递:

1
2
3
4
5
fn print_ref(x: &i32) {
println!("{}", x);
}

print_ref(&100); // 直接传字面量引用,无需 let x = 100;

重要限制:字面量无法获取可变引用 &mut

1
2
3
4
5
6
7
// 编译错误!字面量是临时值,无法修改
// let r: &mut i32 = &mut 42;

// 正确做法:先绑定到可变变量
let mut x = 42;
let r: &mut i32 = &mut x;
*r = 100;

字符串字面量本身就是 &str(静态生命周期),再 & 就是 &&str

1
2
let s1: &str = "hello";       // 字符串切片,类型 &str
let s2: &&str = &"hello"; // 对字符串切片的引用

解构赋值

1
2
let (x, y) = (&1, &2);
let &a = x; // a = 1

闭包捕获

1
2
3
4
5
let s = String::from("hello");
// 闭包借用 s,不转移所有权
let f = || println!("{}", &s);
f();
println!("{}", s); // s 还在

关键规则

规则说明
任意数量不可变引用 OR 一个可变引用不能同时拥有
引用必须有效不能悬垂引用
&T 实现 Copy引用本身可以复制