动态对象字段
动态对象字段允许将对象附加到其他对象。它们与 dynamic_field
类似,但有一些关键区别:
dynamic_object_field
只能存储具有key
能力的对象,这是因为它存储的是对象的 ID,而不是对象本身。dynamic_object_field
提供了一个额外的函数id
,用于返回存储在动态对象字段中的对象的 ID。
何时使用 dynamic_field
与 dynamic_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_field
和 dynamic_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::add
和dof::remove
:用于管理附加的对象字段。df::add
:用于管理附加的非对象字段。- 清理孤儿对象:删除父对象前需要手动清理附加的字段以防止孤儿对象。
最佳实践
- 存储具有
key
能力的对象时使用dynamic_object_field
。 - 存储无
key
能力的结构时使用dynamic_field
。 - 在删除父对象前,先清理动态字段,以避免孤儿对象的产生。
总结
动态对象字段是构建复杂对象关系的强大工具。理解其与 dynamic_field
的区别能够帮助开发者在合适的场景下选择正确的工具,从而构建更强大、更灵活的应用程序。