dynamic_object_field
模块说明
dynamic_object_field(动态对象字段)
特性同dynamic_field(动态字段)
- 与之不同的是值必须具备
key
能力,对象仍然能从外部通过UID
进行访问
源码路径
方法图解
方法说明
分类 | 方法 | 说明 |
---|---|---|
增 | add<...>(object: &mut UID, name: Name, value: Value) | 向对象object 添加名为name 的值为value 的动态字段 |
删 | remove<...>(object: &mut UID, name: Name): Value | 从对象object 中删除名为name 的动态字段,若不存在将会报错 |
改 | borrow_mut<...>(object: &mut UID, name: Name): &mut Value | 从对象object 中获取名为name 的动态字段的可变引用,以便进行对动态字段的修改 |
查 | borrow<...>(object: &UID, name: Name): &Value | 从对象object 中获取名为name 的动态字段的只读引用,用于进行信息查看 |
exists_<...>(object: &UID, name: Name): bool | 若对象object 中存在名为name 的动态字段则返回true ,无需指定value 类型 | |
exists_with_type<...>(object: &UID, name: Name): bool | 若对象object 中存在名为name 的动态字段则返回true ,需指定value 类型 | |
id<Name: copy + drop + store>(object: &UID, name: Name,): Option<ID> | 返回动态对象字段中的对象ID |
代码示例
同样采用书架(Bookshelf
)和书本(Book
)的示例,书本对象作为动态字段添加到书架上,其中书本需要具备key
能力,该对象可以从外部通过 UID
进行访问。
结构定义
注:
Book
结构需要具备key
能力,结构体中也必须具备UID
public struct Bookshelf has key {
id: UID,
book_count: u64
}
public struct Book has key, store {
id: UID,
title: String,
description: String,
}
创建书架共享对象
// 创建书架共享对象
public fun create_bookshelf(ctx: &mut TxContext) {
transfer::share_object(Bookshelf {
id: object::new(ctx),
book_count: 0,
});
}
添加书本到书架
调用
dynamic_field::add
方法。
// 添加书本到书架
public fun add_book(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>, ctx: &mut TxContext) {
let book = Book {
id: object::new(ctx),
title: ascii::string(title),
description: ascii::string(description)
};
dynamic_object_field::add<vector<u8>, Book>(&mut bookshelf.id,title, book);
bookshelf.book_count = bookshelf.book_count + 1;
}
public fun add_book_obj(bookshelf: &mut Bookshelf, book: Book) {
dynamic_object_field::add<vector<u8>, Book>(&mut bookshelf.id,
book.title.into_bytes(), book);
bookshelf.book_count = bookshelf.book_count + 1;
}
获取书本
调用
dynamic_field::borrow
方法。
// 获取书本
public fun get_book(bookshelf: &Bookshelf, title: vector<u8>): &Book {
dynamic_object_field::borrow(&bookshelf.id, title)
}
设置书本的描述信息
调用
dynamic_field::borrow_mut
方法。
// 设置书本的描述信息
public fun set_book_desc(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>) {
let book_mut_ref: &mut Book = dynamic_object_field::borrow_mut(&mut bookshelf.id, title);
book_mut_ref.description = ascii::string(description);
}
判断书本是否存在
调用
dynamic_field::exists_
和dynamic_field::exists_with_type
方法。
public fun is_book_existed(bookshelf: &Bookshelf, title: vector<u8>): bool {
dynamic_object_field::exists_(&bookshelf.id, title)
}
public fun is_book_exists_with_type(bookshelf: &Bookshelf, title: vector<u8>): bool {
dynamic_object_field::exists_with_type<vector<u8>, Book>(&bookshelf.id, title)
}
从书架上移除书本
调用
dynamic_field::remove
和dynamic_field::remove_if_exists
方法。
// 从书架上移除书本
public fun remove_book(bookshelf: &mut Bookshelf, title: vector<u8>): Book {
bookshelf.book_count = bookshelf.book_count - 1;
dynamic_object_field::remove<vector<u8>, Book>(&mut bookshelf.id, title)
}
完整代码
- dynamic_object_field
module cookbook::dynamic_object_field{
use std::ascii::{Self, String};
use sui::dynamic_object_field;
public struct Bookshelf has key {
id: UID,
book_count: u64
}
public struct Book has key, store {
id: UID,
title: String,
description: String,
}
// 创建书架共享对象
public fun create_bookshelf(ctx: &mut TxContext) {
transfer::share_object(Bookshelf {
id: object::new(ctx),
book_count: 0,
});
}
// 放置书本到书架
public fun add_book(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>, ctx: &mut TxContext) {
let book = Book {
id: object::new(ctx),
title: ascii::string(title),
description: ascii::string(description)
};
dynamic_object_field::add<vector<u8>, Book>(&mut bookshelf.id,title, book);
bookshelf.book_count = bookshelf.book_count + 1;
}
public fun add_book_obj(bookshelf: &mut Bookshelf, book: Book) {
dynamic_object_field::add<vector<u8>, Book>(&mut bookshelf.id,
book.title.into_bytes(), book);
bookshelf.book_count = bookshelf.book_count + 1;
}
// 拿取书本
public fun get_book(bookshelf: &Bookshelf, title: vector<u8>): &Book {
dynamic_object_field::borrow(&bookshelf.id, title)
}
// 设置书本的描述信息
public fun set_book_desc(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>) {
let book_mut_ref: &mut Book = dynamic_object_field::borrow_mut(&mut bookshelf.id, title);
book_mut_ref.description = ascii::string(description);
}
// 判断书本是否存在
public fun is_book_existed(bookshelf: &Bookshelf, title: vector<u8>): bool {
dynamic_object_field::exists_(&bookshelf.id, title)
}
public fun is_book_exists_with_type(bookshelf: &Bookshelf, title: vector<u8>): bool {
dynamic_object_field::exists_with_type<vector<u8>, Book>(&bookshelf.id, title)
}
// 从书架上移除书本
public fun remove_book(bookshelf: &mut Bookshelf, title: vector<u8>): Book {
bookshelf.book_count = bookshelf.book_count - 1;
dynamic_object_field::remove<vector<u8>, Book>(&mut bookshelf.id, title)
}
public fun get_book_count(bookshelf: &Bookshelf): u64{
bookshelf.book_count
}
public fun get_book_title(book: &Book): String {
book.title
}
public fun get_book_desc(book: &Book): String {
book.description
}
}
- dynamic_field_tests
#[test_only]
module cookbook::dynamic_object_field_tests {
use std::ascii;
use sui::test_scenario as ts;
use cookbook::dynamic_object_field::{Bookshelf, create_bookshelf, add_book, get_book,
set_book_desc, is_book_existed, is_book_exists_with_type, remove_book,
get_book_count, get_book_title, get_book_desc};
#[test_only]
use sui::test_utils::assert_eq;
#[test]
public fun test_dynamic_object_field() {
let alice = @0xa;
let mut ts = ts::begin(alice);
// 创建书架
{
create_bookshelf(ts.ctx());
};
// 放置书本到书架
let expected_title = b"Mastering Bitcoin";
let expected_description= b"1st Edition";
let expected_new_description= b"3rd Edition";
{
ts.next_tx(alice);
let mut bookshelf: Bookshelf = ts.take_shared();
add_book(
&mut bookshelf,
expected_title,
expected_description,
ts.ctx(),
);
assert_eq(bookshelf.get_book_count(), 1);
ts::return_shared(bookshelf);
};
// 拿取书本
{
ts.next_tx(alice);
let bookshelf: Bookshelf = ts.take_shared();
let book = get_book(
&bookshelf,
expected_title,
);
assert_eq(book.get_book_title(), ascii::string(expected_title));
assert_eq(book.get_book_desc(), ascii::string(expected_description));
ts::return_shared(bookshelf);
};
// 设置书本的描述信息
{
ts.next_tx(alice);
let mut bookshelf: Bookshelf = ts.take_shared();
set_book_desc(
&mut bookshelf,
expected_title,
expected_new_description,
);
let book = get_book(
&bookshelf,
expected_title,
);
assert_eq(book.get_book_title(), ascii::string(expected_title));
assert_eq(book.get_book_desc(), ascii::string(expected_new_description));
ts::return_shared(bookshelf);
};
// 判断书本是否存在
{
ts.next_tx(alice);
let bookshelf: Bookshelf = ts.take_shared();
let is_existed = is_book_existed(
&bookshelf,
expected_title,
);
assert_eq(is_existed, true);
let is_existed = is_book_exists_with_type(
&bookshelf,
expected_title,
);
assert_eq(is_existed, true);
ts::return_shared(bookshelf);
};
// 从书架上移除书本
{
ts.next_tx(alice);
let mut bookshelf: Bookshelf = ts.take_shared();
assert_eq(bookshelf.get_book_count(), 1);
let book = remove_book(
&mut bookshelf,
expected_title,
);
assert_eq(bookshelf.get_book_count(), 0);
assert_eq(book.get_book_title(), ascii::string(expected_title));
assert_eq(book.get_book_desc(), ascii::string(expected_new_description));
bookshelf.add_book_obj(book);
ts::return_shared(bookshelf);
};
ts.end();
}
}