Move —— 引用

引用(Reference)是 Move 中访问数据而不转移所有权的机制。本文介绍引用的工作原理,以及不可变引用(&)和可变引用(&mut)的区别——前者允许只读访问且可多个共存,后者允许读写但具有排他性。

1. 引用(Reference)

Reference 是一种 指针间接寻址 (Pointer Indirection) 机制。它允许我们在栈上创建一个指向堆内存原数据的指针,从而在不进行 所有权转移 (Ownership Transfer) 的前提下访问数据。

2. 不可变引用(&

不可变借用 (Immutable Borrow) —— 创建一个只读指针,允许多个引用同时存在,但严禁修改数据。

语法:

  • 函数参数:s: &Student
  • 传参调用:&s1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public fun get_age(s: &Student): u8 {
// 通过 Reference 进行只读访问 (Read-only Access)
s.age
}

public fun test_immutable() {
let s1 = create_student(18, true, 80, 90);

// 传参时使用 &s1
// 创建 s1 的只读权限,s1 所有权未发生转移
let age1 = get_age(&s1);

// s1 所有权没有丢失,依然活跃,可继续使用
let age2 = s1.age;
}

3. 可变引用(&mut

可变借用 (Mutable Borrow) —— 创建一个读写指针,在特定作用域内具有排他性,允许直接修改堆内存数据。

语法:

  • 函数参数:s: &mut Student
  • 传参调用:&mut s1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public fun set_age(s: &mut Student, new_age: u8) {
// 通过 Reference 进行写入操作 (Write Access)
s.age = new_age;
}

public fun test_mutable() {
// 源变量必须显式标记为 mut
let mut s1 = create_student(18, true, 80, 90);

// 创建 Mutable Reference,修改直接作用于堆内存
set_age(&mut s1, 20);

// 验证修改:数据已变更
let current_age = s1.age;
}

4. 引用时,内存发生了什么?

引用本质上是栈上的一个新指针变量,指向原数据的地址。

1
2
3
4
5
6
7
8
9
10
11
12
       栈 (Stack)                         堆 (Heap)
+-------------------+ +-------------------+
| 变量 s1 | -----------> | Student 数据 |
| (Owner / 所有者) | | age: 18 |
+-------------------+ +-------------------+
⬆️
| 内存地址 (Address)
|
+-------------------+
| 引用 ref |
| (Non-owning Ptr) |
+-------------------+

核心区别:

  • Move (移动): 涉及 所有权转移,栈元数据被浅拷贝给新变量,原变量立即失效 (Uninitialized) 以防止双重释放。
  • Reference (引用):涉及 指针间接寻址,在栈上压入一个新的指针变量指向原数据的内存地址,原变量生命周期不受影响。

5. 总结

Move 用于转移所有权,会导致原变量失效,而 Reference 用于创建数据的临时访问指针——分为”共享只读 (&)”和”独占读写 (&mut)”两种模式,且原变量始终有效。