Move —— Ability 进阶与约束

在泛型编程中,类型参数默认不具备任何能力,需要通过约束来声明。本文深入讲解泛型能力约束的语法,以及 store(允许被嵌套存储)和 key(Sui 对象标识)这两个高级能力的核心机制和使用场景。

1. 泛型约束 (Ability Constraints)

在泛型编程中,由于泛型参数 T 默认 不具备任何能力,编译器为了安全会禁止对其进行 drop (丢弃) 或 copy (复制) 操作。为了操作这些泛型类型,我们需要使用 泛型约束 显式地规定 T 必须具备的能力。

1.1 语法定义

在泛型声明 <T> 后使用冒号 : 添加约束。多个能力之间使用 + 号连接。

1
2
3
4
5
// 单一约束:T 必须有 drop 能力
fun drop<T: drop>(x: T) { ... }

// 多重约束:T 必须同时有 drop 和 copy 能力
fun copy_and_drop<T: drop + copy>(x: T) { ... }

1.2 解决资源处理问题

通过添加 : drop 约束,我们可以修复上一节课中无法自动丢弃泛型变量的问题。

1
2
// 必须在代码里手动拆解,否则代码会报错
let Box { value: _ } = box_u256;

赋予 drop 能力,只要给结构体加上 drop,它就会在离开作用域时自动销毁

1
2
3
4
// 给 Box 加上 drop 能力,只有当 T 也有 drop 时,Box<T> 才有 drop。
public struct Box<T> has drop {
value: T
}

2. store 能力:存储与嵌套

定义: store 能力决定了数据是否可以被 存储 在全局状态中,或者被 嵌套 在其他拥有 store 能力的结构体中。

2.1 传递性规则

store 能力具有传递性:外层结构体若想拥有 store 能力,其内部所有字段的类型也必须拥有 store 能力。

1
2
3
4
// 假设 Cup 需要拥有 store 能力
public struct Cup<T> has store {
item: T
}
  • 场景 ACup<u256>
    • u256 是基本类型,自带 store
    • 结果Cup<u256> 拥有 store 能力。
  • 场景 BCup<Student> (假设 Student 没有 store)
    • Studentstore
    • 结果Cup<Student> 失去 store 能力,无法被存储在链上。

注意: vector<T> 本身拥有 store 能力,但前提是 T 必须有 store。如果 T 没有 store,则 vector<T> 也不能被存储。

3. key 能力:Sui 对象标识

定义: key 能力允许结构体作为 Sui 对象 (Object) 独立存在于区块链的全局存储中。它是资产所有权的核心标识。

3.1 核心规则

  1. 拥有 key 的结构体必须包含一个名为 id 的字段。
  2. 该字段的类型必须是 UID (Unique ID)。
  3. id 字段必须位于结构体的 第一个位置
1
2
3
4
5
6
7
use sui::object::UID;

// 标准的 Sui 对象定义
public struct MyObject has key {
id: UID, // 必须存在,且在第一位
value: u256,
}

拥有 key 能力的结构体可以被转移、共享或冻结,是构建 NFT 和 DeFi 资产的基础。

4. Move 能力总结

能力 (Ability) 描述 核心作用 典型场景
drop 丢弃 允许值离开作用域时自动销毁 临时变量、非资产类数据
copy 复制 允许值被按位复制 (Deep Copy) 基本数据类型、配置参数、状态读取
store 存储 允许被嵌套或存入全局状态 结构体字段、Vector 元素
key 索引 允许作为独立对象存在 (Sui Object) NFT、代币、智能合约状态

5. 代码示例

本示例演示了 Box 结构体如何通过添加能力和约束,从一个普通容器进化为链上可存储的对象组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
use std::debug;

// 给 Box 加上能力
// - store: 让 Box 可以被存到 vector 或其他对象里
// - drop: 让 Box 可以被直接忽略 (前提是 T 也能 drop)
public struct Box<T> has drop, store {
value: T,
}

// key 和 store 的配合
// 这里的 Shelf 是一个 Sui 对象 (has key)
public struct Shelf has key {
id: UID, // 拥有 key 必须有 UID
items: vector<Box<u256>>, // Box<u256> 能放进 vector,是因为它有 store
}

// 创建盒子 (保持不变)
public fun create_box<T>(value: T): Box<T> {
Box { value }
}

#[test]
public fun main() {
let box_u256 = create_box(100);
debug::print(value(&box_u256));

let box_bool = create_box(true);
debug::print(value(&box_bool));

// Before:必须写 let Box { value: _ } = box_u256;
// After:直接调用 drop 函数,或者因为 Box has drop,函数结束自动销毁
// let Box { value: _ } = box_u256;
// let Box { value: _ } = box_bool;


// 因为 Box has store,我们可以把它放进 vector
// 虽然局部 vector 不强制要求 store,但为了放入 Shelf,Box 必须有 store)
let mut vec = vector::empty<Box<bool>>();
vector::push_back(&mut vec, box_bool);

// 验证一下
debug::print(&vector::length(&vec)); // 输出 1

// 作用域结束自动清理 vector
// vector<Box<bool>> 能被 destroy,是因为 Box 和 bool 都有 drop
}

6. 总结

概念 语法 / 关键字 核心作用
泛型约束 T: drop + copy 限制泛型类型必须具备的能力,确保操作安全。
Store 能力 has store 允许结构体被嵌套在其他结构体中,或存储在链上。具有传递性。
Key 能力 has key Sui 对象的标志。结构体必须包含 id: UID,可独立存在于全局存储。
能力体系 Drop, Copy, Store, Key 构成了 Move 语言资源管理和访问控制的基础框架。