动态对象字段 - 将对象作为动态字段存储

你可能会对动态字段有一个疑问 - 如果我们将一个对象存储在动态字段中会怎样? 虽然这是可能的,但将 Sticker 对象作为动态字段存储在 Laptop 上的一个副作用是, Sticker 对象将从存储中移除,无法通过其 id 在链外查找(例如在 Web 界面中)。这与对象包装具有相同的副作用。

public struct Sticker has key, store {
    id: UID,
    image_url: String,
}

public fun add_sticker(laptop: &mut Laptop, name: String, sticker: Sticker) {
    dynamic_field::add(&mut laptop.id, name, sticker);
}

请注意,Sticker 对象也必须具有存储能力才能存储在动态字段中。 因为 Sticker 现在是一个对象,我们还需要通过交易显式地传递它。如果它是一个归属对象,只有所有者才能这样做(所有权规则)。

如果你不希望 Sticker 对象从全局存储中移除,以便你的 Web 界面仍然可以查找它,你可以使用 dynamic_object_field 模块, 而不是 dynamic_field 模块。这两个模块及其功能在 Move 内部看起来几乎相同——关于全局存储的区别仅对链外组件(例如 Web 界面)有影响。

use sui::dynamic_object_field;

public struct Sticker has key, store {
    id: UID,
    image_url: String,
}

public fun add_sticker(laptop: &mut Laptop, name: String, sticker: Sticker) {
    dynamic_object_field::add(&mut laptop.id, name, sticker);
}

一般来说,动态对象字段比动态字段更适合用于动态存储对象。只有在你有意将对象从全局存储中移除时才应使用动态字段。 例如,当你给你的 SuiFren 戴上帽子时,你希望帽子从全局存储中消失,以表示它已被领取。

额外信息:你可能会好奇,当一个对象被添加为另一个对象的动态字段后,这个对象的所有权会发生什么变化。 答案是它将由动态字段本身拥有!在幕后,当动态字段被添加时,每个字段会秘密地创建为全局存储中与定义该字段的父对象绑定的一个单独对象。

这个动态字段对象将拥有添加到它的对象。在上面的例子中,Laptop 拥有 sticker 动态字段,而 sticker 动态字段拥有 Sticker 对象。 是不是很困惑?大多数开发人员其实不需要知道这些细节