动态字段
在之前的课程中,我们深入探讨了对象,并创建了具有自身属性的 SuiFrens 对象以及告诉 Web 界面如何显示它们的 display
对象。
我们还讨论了以下主题:
- 嵌套结构体:具有存储能力的结构体可以嵌入到另一个结构体中。这通常用于非对象结构体,以将长列表的字段划分为逻辑组件。
- 对象包装:将一个 SuiFren 放入另一个对象中。这也使用了存储能力,但实际上从存储中移除了被包装的对象。 被包装到 GiftBoxes 中的 SuiFren 在按对象搜索时将不再被查找。
在本课中,我们将讨论另一种将结构体和对象组合在一起的方法——动态字段。您可以将动态字段视为未在对象结构体上显式定义的“隐形”字段。 假设我们有一个具有以下初始属性的 Laptop 对象:
public struct Laptop has key {
id: UID,
screen_size: u64,
model: u64,
}
假设我们想在将来为这台笔记本电脑动态添加更多的属性,但还不知道这些属性到底是什么。 我们不能立即在结构体中定义它们。这时动态字段就派上用场了——你不需要知道所有要添加到对象的字段,因为这些属性可以作为动态字段添加!
use sui::dynamic_field;
public fun add_attribute(laptop: &mut Laptop, name: String, value: u64) {
dynamic_field::add(&mut laptop.id, name, value);
}
为了给对象添加动态字段,您需要该对象的可变引用。请记住,对于归属对象,只有所有者可以发送使用其对象的可变/不可变引用或值的交易。
共享对象可以被任何人修改。添加动态字段可以简单地通过 dynamic_field::add
,使用可变对象的 id、键和值来完成。
键和值可以是基本类型(数字、字符串等)或结构体。注意,作为键使用的结构体必须具有 copy
、drop
和 store
能力,
而作为值使用的结构体必须具有 store
能力。
public struct StickerName has copy, drop, store {
name: String,
}
public struct Sticker has store {
image_url: String,
}
public fun add_sticker(laptop: &mut Laptop, name: String, image_url: String) {
let sticker_name = StickerName { name };
let sticker = Sticker { image_url };
dynamic_field::add(&mut laptop.id, sticker_name, sticker);
}
动态字段的名称是独特的,所以你不能多次添加相同名称的字段。
要读取或修改动态字段,分别需要对象的不可变引用和可变引用以及字段名称(键)。
如果字段名称是一个结构体,你需要结构体的值本身,这就是为什么作为键使用的结构体必须具有 copy
和 drop
能力的原因。
public fun read_image_url(laptop: &Laptop, name: String): String {
let sticker_name = StickerName { name };
let sticker_reference: &Sticker = dynamic_field::borrow(&laptop.id, sticker_name);
sticker_reference.image_url
}
public fun set_image_url(laptop: &mut Laptop, name: String, new_url: String) {
let sticker_name = StickerName { name };
let sticker_mut_reference: &mut Sticker = dynamic_field::borrow_mut(&mut laptop.id, sticker_name);
sticker_mut_reference.image_url = new_url;
}
请注意,通常你需要指定借用字段的类型(在上面的示例中为 &Sticker 和 &mut Sticker)。 你也可以使用可变对象引用和键来移除现有的动态字段:
public fun remove_sticker(laptop: &mut Laptop, name: String) {
let sticker_name = StickerName { name };
dynamic_field::remove(&mut laptop.id, sticker_name);
}
你可以使用 dynamic_field::exists_(&laptop.id, sticker_name)
来检查动态字段是否存在。