{"author":{"address":"0xbdd3203FeD7bC268DC76BFF731E78C73f76053C1","user":"https://learnblockchain.cn/people/17384"},"content":{"body":"## 前言\r\n\r\n在 Sui 区块链中，对象是其独特的核心特性。通过对象，开发者可以灵活地管理链上的数据，并以创新的方式构建复杂的功能。在这篇博客中，我们将全面介绍 Sui 区块链中的三种对象组合方法及其适用场景：**对象包装**、**动态字段**和**动态对象字段**。\r\n![image.png](https://img.learnblockchain.cn/attachments/2024/12/hTtY8mF7675ad5aed970c.png)\r\n\r\n---\r\n# Move 共学活动：快速上手 Move 开发\r\n为了帮助更多开发者快速了解和掌握 Move 编程语言，**Move 共学**活动由 **HOH 社区**、**HackQuest**、**OpenBuild**、**KeyMap** 联合发起。该活动旨在为新手小白提供一个良好的学习平台，带领大家一步步熟悉 Move 语言，并了解如何将其应用到 Web3 开发中。\r\n\r\n通过与 Move 领域的专业导师们合作，参与者可以快速掌握 Move 语言的基础知识，逐步向更复杂的应用开发进阶。无论是区块链初学者，还是有一定开发经验的工程师，都能从中获益。\r\n\r\n**资源链接：**\r\n- [sui官方文档🚪](https://docs.sui.io/)：获取关于 Sui 链的详细文档，包括开发指南、API 参考等。\r\n- [move学习B站视频🚪](https://www.bilibili.com/video/BV1BMD8Y2EfE/)：通过 B 站的视频教程，跟随导师学习 Move 编程语言的基础与进阶。\r\n- [letsmove仓库🚪](https://github.com/move-cn/letsmove)：这是一个 Move 学习资源的 GitHub 仓库，包含了各种示例代码和教程，帮助开发者掌握 Move 语言。\r\n\r\n\r\n---\r\n\r\n## 对象包装：基础的对象嵌套\r\n\r\n对象包装是将一个对象存储在另一个对象中的过程。这通常意味着内嵌的对象将从全局存储中移除，从而无法通过其 ID 查找。这种方法适合用于将对象转化为非对象的结构体实例。\r\n\r\n### 示例\r\n\r\n以下是一个将 `SuiFren` 对象包装到 `GiftBox` 中的示例：\r\n\r\n```\r\nentry fun wrap_fren(fren: SuiFren, ctx: \u0026mut TxContext) {\r\n    let gift_box = GiftBox {\r\n        id: object::new(ctx),\r\n        inner: fren,\r\n    };\r\n    transfer::transfer(gift_box, tx_context::sender(ctx));\r\n}\r\n```\r\n\r\n在上述代码中，`SuiFren` 被存储到 `GiftBox` 中，并且 `GiftBox` 对象随后被转移到发送者账户。\r\n\r\n### 注意事项\r\n\r\n1. **移除全局存储**：被包装的对象无法直接通过其 ID 查找。\r\n2. **适用场景**：适合需要隐藏对象或将对象作为更复杂结构一部分的场景。\r\n\r\n***\r\n\r\n## 动态字段：灵活的属性扩展\r\n\r\n动态字段允许为对象动态添加字段，而无需预先在结构体中定义它们。这种方法特别适合在设计时无法预见所有字段的场景。\r\n\r\n### 示例\r\n\r\n我们定义一个 `Laptop` 对象，并为其动态添加属性：\r\n\r\n```\r\nuse sui::dynamic_field;\r\n\r\npublic struct Laptop has key {\r\n    id: UID,\r\n    screen_size: u64,\r\n    model: u64,\r\n}\r\n\r\npublic fun add_attribute(laptop: \u0026mut Laptop, name: String, value: u64) {\r\n    dynamic_field::add(\u0026mut laptop.id, name, value);\r\n}\r\n```\r\n\r\n在这个例子中，通过 `dynamic_field::add` 方法，任意键值对可以被动态添加到 `Laptop` 对象。\r\n\r\n### 高级应用\r\n\r\n动态字段不仅可以存储基本类型，还可以存储结构体。例如，为 `Laptop` 添加贴纸属性：\r\n\r\n```\r\npublic struct StickerName has copy, drop, store {\r\n    name: String,\r\n}\r\n\r\npublic struct Sticker has store {\r\n    image_url: String,\r\n}\r\n\r\npublic fun add_sticker(laptop: \u0026mut Laptop, name: String, image_url: String) {\r\n    let sticker_name = StickerName { name };\r\n    let sticker = Sticker { image_url };\r\n    dynamic_field::add(\u0026mut laptop.id, sticker_name, sticker);\r\n}\r\n```\r\n\r\n### 读取与修改动态字段\r\n\r\n动态字段可以通过键来读取和修改：\r\n\r\n```\r\npublic fun read_image_url(laptop: \u0026Laptop, name: String): String {\r\n    let sticker_name = StickerName { name };\r\n    let sticker_reference: \u0026Sticker = dynamic_field::borrow(\u0026laptop.id, sticker_name);\r\n    sticker_reference.image_url\r\n}\r\n\r\npublic fun set_image_url(laptop: \u0026mut Laptop, name: String, new_url: String) {\r\n    let sticker_name = StickerName { name };\r\n    let sticker_mut_reference: \u0026mut Sticker = dynamic_field::borrow_mut(\u0026mut laptop.id, sticker_name);\r\n    sticker_mut_reference.image_url = new_url;\r\n}\r\n```\r\n\r\n### 删除动态字段\r\n\r\n通过 `dynamic_field::remove` 方法，可以移除动态字段：\r\n\r\n```\r\npublic fun remove_sticker(laptop: \u0026mut Laptop, name: String) {\r\n    let sticker_name = StickerName { name };\r\n    dynamic_field::remove(\u0026mut laptop.id, sticker_name);\r\n}\r\n```\r\n\r\n### 注意事项\r\n\r\n1. **唯一性**：动态字段的名称必须唯一。\r\n\r\n2. **能力约束**：\r\n\r\n   * 作为键的结构体必须具备 `copy`、`drop` 和 `store` 能力。\r\n   * 作为值的结构体必须具备 `store` 能力。\r\n\r\n3. **存储移除**：当动态字段存储对象时，对象将从全局存储中移除。\r\n\r\n***\r\n\r\n## 动态对象字段：动态字段的改进\r\n\r\n动态对象字段与动态字段类似，但一个关键区别在于它不会将对象从全局存储中移除。这使其在链外组件（例如 Web 界面）中更容易查找。\r\n\r\n### 示例\r\n\r\n为 `Laptop` 添加一个动态对象字段：\r\n\r\n```\r\nuse sui::dynamic_object_field;\r\n\r\npublic struct Sticker has key, store {\r\n    id: UID,\r\n    image_url: String,\r\n}\r\n\r\npublic fun add_sticker(laptop: \u0026mut Laptop, name: String, sticker: Sticker) {\r\n    dynamic_object_field::add(\u0026mut laptop.id, name, sticker);\r\n}\r\n```\r\n\r\n在这个示例中，`Sticker` 对象被存储为动态对象字段，而不会从全局存储中移除。\r\n\r\n### 注意事项\r\n\r\n1. **对象可见性**：与动态字段不同，动态对象字段保留对象的全局可见性。\r\n2. **适用场景**：适合需要保持对象可查找的场景，例如 Web 界面。\r\n\r\n***\r\n\r\n## 对象组合方法的选择指南\r\n\r\n在设计 Sui 区块链应用时，选择合适的对象组合方法至关重要：\r\n\r\n| 方法     | 全局存储可见性 | 动态添加字段 | 适用场景 |\r\n| ------ | ------- | ------ | ---- |\r\n| 对象包装   | 否       | 否      | 简单嵌套 |\r\n| 动态字段   | 否       | 是      | 灵活扩展 |\r\n| 动态对象字段 | 是       | 是      | 保持可见 |\r\n\r\n### 实际应用建议\r\n\r\n1. **字段是否应显式定义**：如果字段需要显式呈现，优先考虑对象包装或动态对象字段。\r\n2. **是否需要移除全局存储**：如果希望对象从全局存储中移除，选择对象包装或动态字段。\r\n3. **动态字段数量**：尽量控制动态字段的数量（建议少于 10 个）。\r\n\r\n***\r\n\r\n## 总结\r\n\r\nSui 区块链提供了丰富的对象组合方法，为开发者提供了极大的灵活性。通过选择合适的方法，可以在功能性和可维护性之间取得平衡。在实际开发中，建议根据具体需求灵活应用上述三种方法，以充分发挥 Sui 区块链的潜力。","title":"深入了解 Sui 区块链的动态字段和对象组合"},"history":null,"timestamp":1734018246,"version":1}