Move —— 所有权与 Copy 能力

所有权(Ownership)是 Move 语言的核心特性,用于在编译期保证资产安全、防止双重支付。本文介绍所有权的基本规则、移动(Move)语义如何使原变量失效,以及 copy 能力如何让值可以被复制而非转移。

1. 所有权(Ownership)

在 Move 语言中,为了保证资产安全(防止双重支付),有如下规则:

  1. 每个值都有一个所有者(owner)。
  2. 对于不实现 Copy 的类型,同一时间只能有一个所有者(即移动语义)。
  3. 当所有者离开作用域时,值会被自动丢弃,内存释放。

2. 移动(Move)

基于”只能有一个所有者”的规则,当我们把一个变量赋值给另一个变量时,所有权会发生转移。原变量会立即失效。这被称为 Move(移动)

2.1 所有权的转移

假设我们的 Student 结构体只有 drop 能力:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 此时 Student 只有 drop,没有 copy
public struct Student has drop { ... }

public fun test_ownership() {
// 1. s1 是这个 Student 结构体的所有者
let s1 = create_student(18, true, 80, 90);

// 2. 发生"移动":所有权从 s1 转移给了 s2
// 原因:为了保证"唯一所有者",s1 必须放弃所有权。
let s2 = s1;

// 错误:s1 已经失效,不能再使用
// Error: Invalid usage of previously moved variable 's1'.
let age = s1.age;

// 正确:s2 是现在的合法所有者
let age2 = s2.age;
}

2.2 内存发生了什么?

1
2
3
4
5
6
7
8
9
10
栈 (Stack)                    堆 (Heap)
+------------------+ +------------------+
| 变量 s1 | ❌ | Student 结构体 |
| (已失效/Invalid) | - - - -> | |
+------------------+ | age: 18 |
| isMale: true |
+------------------+ | |
| 变量 s2 | =======> | |
| (新所有者) | +------------------+
+------------------+

3. Copy 能力

有些数据(如普通的成绩单、配置信息)并不需要严格的”唯一性”。我们希望在赋值时,复制一份新的数据,保留原数据。这时需要使用 copy 能力。

3.1 复制(Copy)

注意: 类似于 drop,如果外层结构体需要 copy,内部嵌套的结构体(Grades)也必须有 copy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 修改定义:添加 copy 能力
public struct Student has drop, copy {
age: u8,
isMale: bool,
grades: Grades,
}

// 内部结构体也必须加 copy
public struct Grades has drop, copy {
literature: u64,
math: u64,
}

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

// 发生"复制":因为有 copy 能力
// 系统在堆上克隆了一份数据给 s2。s1 依然保留自己的所有权。
let s2 = s1;

// 正确:s1 和 s2 现在是两份独立的数据,互不影响
let age1 = s1.age;
let age2 = s2.age;
}

3.2 内存发生了什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
栈 (Stack)                    堆 (Heap)
+------------------+ +------------------+
| 变量 s1 | -------> | Student (A) |
| | | age: 18 |
+------------------+ +------------------+

Let s2 = s1 (Copy)
⬇️

+------------------+ +------------------+
| 变量 s2 | -------> | Student (B) |
| | | age: 18 |
+------------------+ +------------------+

4. 什么时候用 Copy?

  • Move (默认):适用于资产(如 Token、NFT)。像现金一样,给出去就没有了。
  • Copy:适用于普通数据(如 u64、状态配置)。像文档一样,可以复印无数份。