{"author":{"address":null,"user":"https://learnblockchain.cn/people/13838"},"content":{"body":"# sui-move进阶：table\r\n\r\nSui Move 中的 `0x2::table` 模块提供了一种类似映射（Map）的集合，用于存储键值对。与传统集合不同，`Table` 的键和值并不直接存储在 `Table` 结构体中，而是通过 Sui 的对象系统进行管理。这使得 `Table` 成为一个句柄，用于操作存储在对象系统中的数据。\r\n\r\n---\r\n\r\n## Table 的特性\r\n\r\n### 存储在对象系统中\r\n\r\n   - 键值对不直接存储在 `Table` 实例中，而是分散存储在 Sui 的对象系统中。\r\n\r\n   - 不同的 `Table` 即使有相同的键值对，也不会在运行时被认为相等。\r\n\r\n我们可以来看看table的源码：\r\n```move\r\npublic struct Table\u003cphantom K: copy + drop + store, phantom V: store\u003e has key, store {\r\n    /// the ID of this table\r\n    id: UID,\r\n    /// the number of key-value pairs in the table\r\n    size: u64,\r\n}\r\n```\r\n\r\n可以看到table只有两个内部变量：id 和size：\r\n - id 赋予table 唯一的标识（这也是拥有key能力的资源所必须的）\r\n\r\n - size标记table的大小，有多少个键值对就有多少个size \r\n\r\n在来看一个基本的table库函数的定义：\r\n\r\n```move\r\n/// Adds a key-value pair to the table `table: \u0026mut Table\u003cK, V\u003e`\r\n/// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the table already has an entry with\r\n/// that key `k: K`.\r\npublic fun add\u003cK: copy + drop + store, V: store\u003e(table: \u0026mut Table\u003cK, V\u003e, k: K, v: V) {\r\n    field::add(\u0026mut table.id, k, v);\r\n    table.size = table.size + 1;\r\n}\r\n```\r\n\r\n这里调用了dynamic_field库中的add函数，这部分我将在后续单独将该库的时候去分析，这里我们只需知道：\r\n\r\n\u003e K是一个拥有copy 、drop 、store能力的对象，V是一个拥有store能力的对象。该函数的作用是向Table添加一个由K指定的V动态对象。\r\n\r\n示例：\r\n   ```move\r\n   let table1 = table::new\u003cu64, bool\u003e();\r\n   let table2 = table::new\u003cu64, bool\u003e();\r\n   table::add(\u0026mut table1, 0, false);\r\n   table::add(\u0026mut table1, 1, true);\r\n   table::add(\u0026mut table2, 0, false);\r\n   table::add(\u0026mut table2, 1, true);\r\n   assert!(\u0026table1 != \u0026table2); // 两个 Table 不相等\r\n高效的动态存储：\r\n```\r\n\r\n通过 Sui 的对象系统管理存储，提升了存储和检索的灵活性。\r\n\r\n## 核心操作\r\n\r\n以下是 0x2::table 模块中支持的核心操作：\r\n\r\n### 创建 Table\r\n\r\nnew 函数用于创建一个新的空表：\r\n```move\r\n/// Creates a new, empty table\r\npublic fun new\u003cK: copy + drop + store, V: store\u003e(ctx: \u0026mut TxContext): Table\u003cK, V\u003e {\r\n    Table {\r\n        id: object::new(ctx),\r\n        size: 0,\r\n    }\r\n}\r\n```\r\n示例：\r\n\r\n```move\r\nlet table = table::new\u003cu64, bool\u003e(\u0026mut ctx);\r\n```\r\n\r\n### 添加键值对\r\n\r\nadd 函数用于向 Table 添加键值对：\r\n\r\n```move\r\n/// Adds a key-value pair to the table `table: \u0026mut Table\u003cK, V\u003e`\r\n/// Aborts with `sui::dynamic_field::EFieldAlreadyExists` if the table already has an entry with\r\n/// that key `k: K`.\r\npublic fun add\u003cK: copy + drop + store, V: store\u003e(table: \u0026mut Table\u003cK, V\u003e, k: K, v: V) {\r\n    field::add(\u0026mut table.id, k, v);\r\n    table.size = table.size + 1;\r\n}\r\n```\r\n\r\n如果该键已存在，将会抛出`sui::dynamic_field::EFieldAlreadyExists`错误。\r\n\r\n示例：\r\n```move\r\ntable::add(\u0026mut table, 42, true);\r\n```\r\n\r\n### 借用键对应的值\r\n\r\n#### 不可变借用:\r\n\r\nborrow 函数返回键对应的值的不可变引用：\r\n\r\n```move\r\n#[syntax(index)]\r\n/// Immutable borrows the value associated with the key in the table `table: \u0026Table\u003cK, V\u003e`.\r\n/// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with\r\n/// that key `k: K`.\r\npublic fun borrow\u003cK: copy + drop + store, V: store\u003e(table: \u0026Table\u003cK, V\u003e, k: K): \u0026V {\r\n    field::borrow(\u0026table.id, k)\r\n}\r\n```\r\n\r\n如果键不存在，会中止并抛出 `EFieldDoesNotExist` 错误。\r\n\r\n示例：\r\n```move\r\nlet value = table::borrow(\u0026table, 42);\r\n```\r\n\r\n#### 可变借用\r\n\r\nborrow_mut 函数返回键对应的值的可变引用：\r\n\r\n```move\r\n#[syntax(index)]\r\n/// Mutably borrows the value associated with the key in the table `table: \u0026mut Table\u003cK, V\u003e`.\r\n/// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with\r\n/// that key `k: K`.\r\npublic fun borrow_mut\u003cK: copy + drop + store, V: store\u003e(table: \u0026mut Table\u003cK, V\u003e, k: K): \u0026mut V {\r\n    field::borrow_mut(\u0026mut table.id, k)\r\n}\r\n```\r\n\r\n示例：\r\n```move\r\nlet value_mut = table::borrow_mut(\u0026mut table, 42);\r\n*value_mut = false; // 修改值\r\n```\r\n\r\n### 移除键值对\r\n\r\nremove 函数用于移除键值对并返回对应的值：\r\n\r\n```move\r\n/// Removes the key-value pair in the table `table: \u0026mut Table\u003cK, V\u003e` and returns the value.\r\n/// Aborts with `sui::dynamic_field::EFieldDoesNotExist` if the table does not have an entry with\r\n/// that key `k: K`.\r\npublic fun remove\u003cK: copy + drop + store, V: store\u003e(table: \u0026mut Table\u003cK, V\u003e, k: K): V {\r\n    let v = field::remove(\u0026mut table.id, k);\r\n    table.size = table.size - 1;\r\n    v\r\n}\r\n```\r\n\r\n如果键不存在，会中止并抛出 `EFieldDoesNotExist` 错误。\r\n\r\n示例：\r\n```move\r\nlet value = table::remove(\u0026mut table, 42);\r\n```\r\n\r\n### 检查键是否存在\r\n\r\ncontains 函数用于检查键是否存在于 Table 中：\r\n\r\n```move\r\n/// Returns true iff there is a value associated with the key `k: K` in table `table: \u0026Table\u003cK, V\u003e`\r\npublic fun contains\u003cK: copy + drop + store, V: store\u003e(table: \u0026Table\u003cK, V\u003e, k: K): bool {\r\n    field::exists_with_type\u003cK, V\u003e(\u0026table.id, k)\r\n}\r\n```\r\n\r\n示例：\r\n```move\r\nlet exists = table::contains(\u0026table, 42);\r\n```\r\n\r\n### 获取 Table 的大小\r\n\r\n获取长度:\r\n    \r\n    length 函数返回 Table 中的键值对数量：\r\n\r\n```move\r\n/// Returns the size of the table, the number of key-value pairs\r\npublic fun length\u003cK: copy + drop + store, V: store\u003e(table: \u0026Table\u003cK, V\u003e): u64 {\r\n    table.size\r\n}\r\n```\r\n\r\n### 检查是否为空\r\n\r\nis_empty 函数返回 Table 是否为空：\r\n\r\n```move\r\n/// Returns true iff the table is empty (if `length` returns `0`)\r\npublic fun is_empty\u003cK: copy + drop + store, V: store\u003e(table: \u0026Table\u003cK, V\u003e): bool {\r\n    table.size == 0\r\n}\r\n```\r\n\r\n示例：\r\n\r\n```move\r\nlet size = table::length(\u0026table);\r\nlet empty = table::is_empty(\u0026table);\r\n```\r\n\r\n### 销毁 Table\r\n\r\n销毁空表:\r\n\r\n    destroy_empty 函数销毁一个空的 Table：\r\n\r\n```move\r\n/// Destroys an empty table\r\n/// Aborts with `ETableNotEmpty` if the table still contains values\r\npublic fun destroy_empty\u003cK: copy + drop + store, V: store\u003e(table: Table\u003cK, V\u003e) {\r\n    let Table { id, size } = table;\r\n    assert!(size == 0, ETableNotEmpty);\r\n    id.delete()\r\n}\r\n```\r\n如果 Table 非空，会中止并抛出 `ETableNotEmpty` 错误。\r\n\r\n### 销毁任意 Table\r\n\r\ndrop 函数可销毁可能非空的 Table，要求值类型 V 具有 drop 能力：\r\n\r\n```move\r\n/// Drop a possibly non-empty table.\r\n/// Usable only if the value type `V` has the `drop` ability\r\npublic fun drop\u003cK: copy + drop + store, V: drop + store\u003e(table: Table\u003cK, V\u003e) {\r\n    let Table { id, size: _ } = table;\r\n    id.delete()\r\n}\r\n```\r\n\r\n示例：\r\n\r\n```move\r\nif table::is_empty(\u0026table) {\r\n    table::destroy_empty(table);\r\n} else {\r\n    table::drop(table);\r\n}\r\n```\r\n\r\n## 总结\r\n0x2::table 是 Sui Move 中提供的一个高效键值存储结构，通过 Sui 的对象系统管理存储，实现了灵活且安全的动态存储。\r\n\r\n- 关键特性\r\n    - 使用对象系统存储键值对，提升了扩展性。\r\n    - 支持基础的增删改查操作。\r\n    - 静态验证所有权规则，防止数据竞争和内存错误。\r\n- 常见用途\r\n    - 实现复杂的智能合约逻辑，如动态存储和检索数据。\r\n    - 高效管理全局状态中的数据。\r\n    - 通过 Sui 对象系统扩展合约的功能。\r\n\r\n学习过其他语言HashMap或者其他Map结构的朋友应该可以比较容易的理解本库的内容和用法，基本是没有差别的。\r\n\r\n但这是区块链，我们可以看到每一个键值都拥有key或者store能力，这意味着它们都将存储在链上，所以你或许需要注意一下开销：\r\n\r\n\u003e如果不想要开销超出预期的话，尽量减少需要存储在链上的数据。\r\n\u003e除非你知道你正在做什么，并对未来需要进行的操作和可能的开销\r\n\u003e存在预期。","title":"sui-move进阶：table"},"history":null,"timestamp":1734012913,"version":1}