动态集合

Sui 框架提供了多种集合类型,基于动态字段动态对象字段的概念构建。这些集合类型旨在以更安全和更易理解的方式存储和管理动态字段和对象。

对于每种集合类型,我们将指定它们使用的基本类型和它们提供的特定功能。

与操作 UID 的动态(对象)字段不同,集合类型具有自己的类型,并允许调用关联函数

公共概念

所有集合类型共享相同的一组方法,包括:

  • add - 将字段添加到集合中
  • remove - 从集合中移除字段
  • borrow - 从集合中借用字段
  • borrow_mut - 从集合中借用可变引用字段
  • contains - 检查集合中是否存在字段
  • length - 返回集合中字段的数量
  • is_empty - 检查length是否为0

所有集合类型都支持对borrowborrow_mut方法使用索引语法。如果在示例中看到方括号,它们将被转换为对borrowborrow_mut的调用。

let hat: &Hat = &bag[b"key"];
let hat_mut: &mut Hat = &mut bag[b"key"];

// 等同于
let hat: &Hat = bag.borrow(b"key");
let hat_mut: &mut Hat = bag.borrow_mut(b"key");

在示例中,我们不会专注于这些函数,而是关注集合类型之间的区别。

Bag

正如其名,Bag 表示一组异构值的“袋子”。它是一个简单的非泛型类型,可以存储任何数据。Bag 永远不会允许存在孤立的字段,因为它会跟踪字段的数量,如果不是空的,则不能销毁它。

// 文件:sui-framework/sources/bag.move
public struct Bag has key, store {
    /// 此 Bag 的 ID
    id: UID,
    /// Bag 中键值对的数量
    size: u64,
}

由于 Bag 存储任何类型,它提供了额外的方法:

  • contains_with_type - 检查是否存在特定类型的字段

作为结构字段使用:

/// Imported from the `sui::bag` module.
use sui::bag::{Self, Bag};

/// An example of a `Bag` as a struct field.
public struct Carrier has key {
    id: UID,
    bag: Bag
}

使用 Bag:

let mut bag = bag::new(ctx);

// bag has the `length` function to get the number of elements
assert!(bag.length() == 0, 0);

bag.add(b"my_key", b"my_value".to_string());

// length has changed to 1
assert!(bag.length() == 1, 1);

// in order: `borrow`, `borrow_mut` and `remove`
// the value type must be specified
let field_ref: &String = &bag[b"my_key"];
let field_mut: &mut String = &mut bag[b"my_key"];
let field: String = bag.remove(b"my_key");

// length is back to 0 - we can unpack
bag.destroy_empty();

ObjectBag

sui::object_bag模块中定义。与 Bag 相同,但在内部使用动态对象字段。只能存储对象作为值。

Table

Table 是一个具有固定键和值类型的类型化动态集合。它在sui::table模块中定义。

// 文件:sui-framework/sources/table.move
public struct Table<phantom K: copy + drop + store, phantom V: store> has key, store {
    /// 此 Table 的 ID
    id: UID,
    /// Table 中键值对的数量
    size: u64,
}

作为结构字段使用:

/// Imported from the `sui::table` module.
use sui::table::{Self, Table};

/// Some record type with `store`
public struct Record has store { /* ... */ }

/// An example of a `Table` as a struct field.
public struct UserRegistry has key {
    id: UID,
    table: Table<address, Record>
}

使用 Table:

#[test] fun test_table() {
let ctx = &mut tx_context::dummy();

// Table requires explicit type parameters for the key and value
// ...but does it only once in initialization.
let mut table = table::new<address, String>(ctx);

// table has the `length` function to get the number of elements
assert!(table.length() == 0, 0);

table.add(@0xa11ce, b"my_value".to_string());
table.add(@0xb0b, b"another_value".to_string());

// length has changed to 2
assert!(table.length() == 2, 2);

// in order: `borrow`, `borrow_mut` and `remove`
let addr_ref = &table[@0xa11ce];
let addr_mut = &mut table[@0xa11ce];

// removing both values
let _addr = table.remove(@0xa11ce);
let _addr = table.remove(@0xb0b);

// length is back to 0 - we can unpack
table.destroy_empty();

ObjectTable

sui::object_table模块中定义。与 Table 相同,但在内部使用动态对象字段。只能存储对象作为值。

概要

  • Bag - 一个简单的集合,可以存储任何类型的数据
  • ObjectBag - 一个只能存储对象的集合
  • Table - 一个具有固定键和值类型的类型化动态集合
  • ObjectTable - 与 Table 相同,但只能存储对象

LinkedTable

此部分即将推出!