Skip to content

动态对象字段

动态对象字段允许将对象附加到其他对象。它们与 dynamic_field 类似,但有一些关键区别:

  • dynamic_object_field 只能存储具有 key 能力的对象,这是因为它存储的是对象的 ID,而不是对象本身。
  • dynamic_object_field 提供了一个额外的函数 id,用于返回存储在动态对象字段中的对象的 ID。

何时使用 dynamic_fielddynamic_object_field

  • 如果需要存储不具有 key 能力的结构,例如元数据,则应使用 dynamic_field
  • 如果需要存储具有 key 能力的对象,例如配件,则应使用 dynamic_object_field

使用动态对象字段

sui::dynamic_object_field 模块提供了一组函数来管理动态对象字段。这些函数与 sui::dynamic_field 模块中的函数类似,但针对存储具有 key 能力的对象进行了优化。以下是常用的函数:

  • add:向对象添加一个动态对象字段。
  • remove:从对象中移除一个动态对象字段。
  • borrow:从对象中借用一个动态对象字段。
  • borrow_mut:从对象中借用一个动态对象字段的可变引用。
  • exists_:检查某个动态对象字段是否存在。
  • exists_with_type:检查某个动态对象字段是否存在并具有特定类型。
  • id:返回动态对象字段中存储对象的 ID。

动态对象字段示例

以下是一个使用 dynamic_object_fielddynamic_field 的示例,用于将配件和元数据附加到角色对象:

move
use std::string::String;
use sui::dynamic_object_field as dof;
use sui::dynamic_field as df;

// 角色对象,具有 `key` 能力
public struct Character has key {
    id: UID,
}

// 元数据结构,无 `key` 能力
public struct Metadata has store, drop {
    name: String,
}

// 配件对象,具有 `key` 和 `store` 能力
public struct Accessory has key, store {
    id: UID,
}

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

    // 创建一个角色对象
    let mut character = Character { id: object::new(ctx) };

    // 创建一个配件对象并附加到角色
    let hat = Accessory { id: object::new(ctx) };
    dof::add(&mut character.id, b"hat_key", hat);

    // 创建元数据并附加到角色
    let metadata = Metadata { name: b"John".to_string() };
    df::add(&mut character.id, b"metadata_key", metadata);

    // 借用配件的引用
    let hat_ref: &Accessory = dof::borrow(&character.id, b"hat_key");
    let hat_id = dof::id(&character.id, b"hat_key").extract(); // 提取对象 ID

    // 修改配件
    let hat_mut: &mut Accessory = dof::borrow_mut(&mut character.id, b"hat_key");
    let removed_hat: Accessory = dof::remove(&mut character.id, b"hat_key");

    // 清理对象
    sui::test_utils::destroy(removed_hat);
    sui::test_utils::destroy(character);
}

代码解读

  • Character:作为动态字段附加的对象。
  • Accessory:具有 key 能力的配件,可以通过 dynamic_object_field 存储。
  • Metadata:不具有 key 能力的元数据结构,只能通过 dynamic_field 存储。
  • dof::adddof::remove:用于管理附加的对象字段。
  • df::add:用于管理附加的非对象字段。
  • 清理孤儿对象:删除父对象前需要手动清理附加的字段以防止孤儿对象。

最佳实践

  • 存储具有 key 能力的对象时使用 dynamic_object_field
  • 存储无 key 能力的结构时使用 dynamic_field
  • 在删除父对象前,先清理动态字段,以避免孤儿对象的产生。

总结

动态对象字段是构建复杂对象关系的强大工具。理解其与 dynamic_field 的区别能够帮助开发者在合适的场景下选择正确的工具,从而构建更强大、更灵活的应用程序。