集合
集合类型是编程语言中处理数据集合的核心组件。Sui Framework 提供了一系列基于向量的集合类型,既保持了 vector 的灵活性,又增加了功能性和约束条件。本节介绍这些集合类型及其在实际应用中的用法。
向量(Vector)
在 Move 中,vector 是一种动态数组类型,用于存储任意类型的有序集合。虽然之前已经介绍了 vector 类型,但在集合的上下文中需要进一步探讨其在结构体中的应用场景。
示例:在对象中使用向量
以下代码展示了如何在结构体中定义和操作一个 vector 类型字段。
module book::collections_vector;
use std::string::String;
/// 代表一本可以出售的图书
public struct Book has key, store {
id: UID, // 图书的唯一标识
name: String, // 图书的名称
}
/// 图书商店结构,包含一组书籍
public struct BookStore has key, store {
id: UID, // 商店的唯一标识
books: vector<Book>, // 商店中的图书集合
}
在上述例子中,BookStore 使用 vector 存储一组 Book 实例。这种模式在需要按顺序管理多个对象时非常常见。
VecSet:唯一元素集合
VecSet 是一种集合类型,专门用于存储一组唯一元素。与 vector 不同,VecSet 会自动排除重复元素,因此适合用来管理唯一标识符或地址列表。
示例:VecSet 的使用
module book::collections_vec_set;
use sui::vec_set::{Self, VecSet};
public struct App has drop {
subscribers: VecSet<address>, // 存储唯一订阅者地址
}
#[test]
fun vec_set_playground() {
let mut set = vec_set::empty<u8>(); // 创建空集合
set.insert(1); // 添加元素 1
set.insert(2);
set.insert(3);
assert!(set.contains(&1)); // 检查是否包含元素 1
assert!(set.size() == 3); // 集合大小为 3
assert!(!set.is_empty()); // 集合非空
set.insert(3); // 尝试插入重复元素 3
assert!(set.size() == 3); // 尺寸未改变
set.remove(&2); // 移除元素 2
assert!(!set.contains(&2)); // 集合中不再包含 2
}
注意事项
- 重复插入:如果尝试插入已存在的元素,操作会静默失败,集合的大小不变。
- 元素类型:VecSet 的元素类型必须实现
Ord
能力,以支持排序和去重。
VecMap:键值对集合
VecMap 是一种键值映射集合,用于存储键值对。它类似于哈希表,但在实现上基于向量,因此键的顺序与插入顺序一致。
示例:VecMap 的使用
module book::collections_vec_map;
use sui::vec_map::{Self, VecMap};
use std::string::String;
public struct Metadata has drop {
name: String, // 元数据的名称
attributes: VecMap<String, String>, // 属性的键值映射
}
#[test]
fun vec_map_playground() {
let mut map = vec_map::empty(); // 创建空映射
map.insert(b"id".to_string(), b"12345".to_string()); // 添加键值对
map.insert(b"type".to_string(), b"book".to_string());
assert!(map.contains(&b"id".to_string())); // 检查键是否存在
assert!(map.get(&b"type".to_string()).unwrap() == b"book"); // 获取值
map.remove(&b"id".to_string()); // 移除键值对
}
特性和行为
- 键的唯一性:同一个键只能存在一个值。如果插入重复键,新的值会替换旧值。
- 键的能力要求:键必须实现
Ord
和Copy
能力。
局限性和注意事项
大小限制
集合的大小受到 Move 对象大小的限制。如果集合过大,可能会超出对象限制,导致操作失败。
元素类型
集合类型是严格类型化的。不能将错误类型的元素插入集合,否则会触发编译错误。例如,VecSet<u8>
不能存储 String
类型的元素。
比较行为
集合类型(如 VecSet 和 VecMap)无法直接进行逻辑比较,原因是其内部存储顺序不保证一致。
let mut set1 = vec_set::empty();
set1.insert(1);
set1.insert(2);
let mut set2 = vec_set::empty();
set2.insert(2);
set2.insert(1);
assert!(set1 == set2); // 错误:比较可能失败,尽管元素相同
建议使用显式检查方法(如 contains
或 size
)进行逻辑比较。
总结
- 向量:灵活的动态数组,适用于存储任意有序对象集合。
- VecSet:保证唯一性的集合类型,适合管理去重列表。
- VecMap:键值映射集合,用于存储关联关系。
这些基于向量的集合提供了良好的类型安全性和基本操作能力,但在存储大量数据时受限于 Move 的对象大小限制。在需要更灵活或大规模数据存储的场景下,可以探索其他方法,例如动态字段。