Skip to content

Commit 30c9b1a

Browse files
committed
add collection intro
1 parent 2a23e41 commit 30c9b1a

File tree

6 files changed

+727
-11
lines changed

6 files changed

+727
-11
lines changed

src/05_collection/01.dynamic_field.md

+15-11
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,31 @@
22

33
## 模块说明
44

5-
`dynamic_field(动态字段)`模块定义将结构体和值组合在一起的方式,可以在运行时动态进行添加和删除。任何具有 `store` 能力的值都可以被存储。可以不具备`key`能力,即不可直接从外部进行访问。
5+
- `dynamic_field(动态字段)`模块定义将结构体和值组合在一起
6+
- 可以使用**任意**名字做字段,也可以在运行时**动态**进行添加和删除
7+
- 名称可以是任何拥有 `copy``drop``store` 能力的值,这些值包括基本类型以及拥有相应能力的结构体
8+
- 任何具有 `store` 能力的值都可以被存储
9+
- 可以不具备`key`能力,即不可直接从外部进行访问
610

711
## 源码路径
812

9-
https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/dynamic_field.move
13+
[dynamic_field.move](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/dynamic_field.move)
1014

1115
## 方法图解
1216

1317
![](images/dynamic_field.svg)
1418

1519
## 方法说明
1620

17-
| 分类 | 方法 | 说明 |
18-
| ------ | ------------------------------------------------------ | ------------------------------------------------------------ |
19-
| **** | `add<...>(object: &mut UID, name: Name, value: Value)` | 向对象`object`添加名为`name`的值为`value`的动态字段 |
20-
| **** | `remove<...>(object: &mut UID, name: Name)` | 从对象`object`中删除名为`name`的动态字段,若不存在将会报错 |
21-
| | `remove_if_exists<...>(object: &mut UID, name: Name)` | 从对象`object`中删除名为`name`的动态字段,若存在则已`option::some`包装后返回,若不存在返回`option::none()` |
22-
| **** | `borrow_mut<...>(object: &mut UID, name: Name)` | 从对象`object`中获取名为`name`的动态字段的可变引用,以便进行对动态字段的修改 |
23-
| **** | `borrow<...>(object: &UID, name: Name)` | 从对象`object`中获取名为`name`的动态字段的只读引用,用于进行信息查看 |
24-
| | `exists_<...>(object: &UID, name: Name)` | 若对象`object`中存在名为`name`的动态字段则返回`true`,无需指定`value`类型 |
25-
| | `exists_with_type<...>(object: &UID, name: Name)` | 若对象`object`中存在名为`name`的动态字段则返回`true`,需指定`value`类型 |
21+
| 分类 | 方法 | 说明 |
22+
| ------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
23+
| **** | `add<...>(object: &mut UID, name: Name, value: Value)` | 向对象`object`添加名为`name`的值为`value`的动态字段 |
24+
| **** | `remove<...>(object: &mut UID, name: Name): Value` | 从对象`object`中删除名为`name`的动态字段,若不存在将会报错 |
25+
| | `remove_if_exists<...>(object: &mut UID, name: Name): Option<Value>` | 从对象`object`中删除名为`name`的动态字段,若存在则已`option::some`包装后返回,若不存在返回`option::none()` |
26+
| **** | `borrow_mut<...>(object: &mut UID, name: Name): &mut Value` | 从对象`object`中获取名为`name`的动态字段的可变引用,以便进行对动态字段的修改 |
27+
| **** | `borrow<...>(object: &UID, name: Name): &Value` | 从对象`object`中获取名为`name`的动态字段的只读引用,用于进行信息查看 |
28+
| | `exists_<...>(object: &UID, name: Name): bool` | 若对象`object`中存在名为`name`的动态字段则返回`true`,无需指定`value`类型 |
29+
| | `exists_with_type<...>(object: &UID, name: Name): bool` | 若对象`object`中存在名为`name`的动态字段则返回`true`,需指定`value`类型 |
2630

2731
## 代码示例
2832

src/05_collection/01.vec.md

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
# dynamic_object_field
2+
3+
## 模块说明
4+
5+
- `dynamic_object_field(动态对象字段)`特性同`dynamic_field(动态字段)`
6+
7+
- 与之不同的是值必须具备`key`能力,对象仍然能从外部通过 `UID` 进行访问
8+
9+
## 源码路径
10+
11+
[dynamic_object_field.move](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/dynamic_object_field.move)
12+
13+
## 方法图解
14+
15+
![](images/dynamic_object_field.svg)
16+
17+
## 方法说明
18+
19+
| 分类 | 方法 | 说明 |
20+
| ------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
21+
| **** | `add<...>(object: &mut UID, name: Name, value: Value)` | 向对象`object`添加名为`name`的值为`value`的动态字段 |
22+
| **** | `remove<...>(object: &mut UID, name: Name): Value ` | 从对象`object`中删除名为`name`的动态字段,若不存在将会报错 |
23+
| **** | `borrow_mut<...>(object: &mut UID, name: Name): &mut Value` | 从对象`object`中获取名为`name`的动态字段的可变引用,以便进行对动态字段的修改 |
24+
| **** | `borrow<...>(object: &UID, name: Name): &Value` | 从对象`object`中获取名为`name`的动态字段的只读引用,用于进行信息查看 |
25+
| | `exists_<...>(object: &UID, name: Name): bool` | 若对象`object`中存在名为`name`的动态字段则返回`true`,无需指定`value`类型 |
26+
| | `exists_with_type<...>(object: &UID, name: Name): bool` | 若对象`object`中存在名为`name`的动态字段则返回`true`,需指定`value`类型 |
27+
| | `id<Name: copy + drop + store>(object: &UID, name: Name,): Option<ID>` | 返回动态对象字段中的对象`ID` |
28+
29+
## 代码示例
30+
31+
采用书架(`Bookshelf`)和书本(`Book`)的示例,书本对象作为动态字段添加到书架上,其中书本需要具备`key`能力,该对象可以从外部通过 `UID` 进行访问。
32+
33+
### 结构定义
34+
35+
```rust
36+
// 书架结构定义
37+
public struct Bookshelf has key {
38+
id: UID,
39+
// 书本数量
40+
book_count: u64
41+
}
42+
43+
// 书本结构定义
44+
public struct Book has store {
45+
// 书本标题
46+
title: String,
47+
// 书本描述
48+
description: String,
49+
}
50+
```
51+
52+
### 创建书架共享对象
53+
54+
```rust
55+
public fun create_bookshelf(ctx: &mut TxContext) {
56+
transfer::share_object(Bookshelf {
57+
id: object::new(ctx),
58+
book_count: 0,
59+
});
60+
}
61+
```
62+
63+
### 添加书本到书架
64+
65+
> 调用`dynamic_field::add`方法。
66+
67+
```rust
68+
public fun add_book(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>) {
69+
let book = Book {
70+
title: ascii::string(title),
71+
description: ascii::string(description)
72+
};
73+
74+
dynamic_field::add(&mut bookshelf.id,title, book);
75+
bookshelf.book_count = bookshelf.book_count + 1;
76+
}
77+
```
78+
79+
### 获取书本
80+
81+
> 调用`dynamic_field::borrow`方法。
82+
83+
```rust
84+
public fun get_book(bookshelf: &Bookshelf, title: vector<u8>): &Book {
85+
dynamic_field::borrow(&bookshelf.id, title)
86+
}
87+
```
88+
89+
### 设置书本的描述信息
90+
91+
> 调用`dynamic_field::borrow_mut`方法。
92+
93+
```rust
94+
public fun set_book_desc(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>) {
95+
let book_mut_ref: &mut Book = dynamic_field::borrow_mut(&mut bookshelf.id, title);
96+
book_mut_ref.description = ascii::string(description);
97+
}
98+
```
99+
100+
### 判断书本是否存在
101+
102+
> 调用`dynamic_field::exists_``dynamic_field::exists_with_type`方法。
103+
104+
```rust
105+
public fun is_book_existed(bookshelf: &Bookshelf, title: vector<u8>): bool {
106+
dynamic_field::exists_(&bookshelf.id, title)
107+
}
108+
109+
public fun is_book_exists_with_type(bookshelf: &Bookshelf, title: vector<u8>): bool {
110+
dynamic_field::exists_with_type<vector<u8>, Book>(&bookshelf.id, title)
111+
}
112+
```
113+
114+
### 从书架上移除书本
115+
116+
> 调用`dynamic_field::remove``dynamic_field::remove_if_exists`方法。
117+
118+
```rust
119+
public fun remove_book(bookshelf: &mut Bookshelf, title: vector<u8>): Book {
120+
bookshelf.book_count = bookshelf.book_count - 1;
121+
dynamic_field::remove<vector<u8>, Book>(&mut bookshelf.id, title)
122+
}
123+
124+
public fun remove_if_book_exists(bookshelf: &mut Bookshelf, title: vector<u8>): Option<Book> {
125+
bookshelf.book_count = bookshelf.book_count - 1;
126+
dynamic_field::remove_if_exists<vector<u8>, Book>(&mut bookshelf.id, title)
127+
}
128+
```
129+
130+
## 完整代码
131+
132+
```rust
133+
module cookbook::dynamic_field{
134+
use std::ascii::{Self, String};
135+
use sui::dynamic_field;
136+
137+
public struct Bookshelf has key {
138+
id: UID,
139+
book_count: u64
140+
}
141+
142+
public struct Book has store {
143+
title: String,
144+
description: String,
145+
}
146+
147+
// 创建书架共享对象
148+
public fun create_bookshelf(ctx: &mut TxContext) {
149+
transfer::share_object(Bookshelf {
150+
id: object::new(ctx),
151+
book_count: 0,
152+
});
153+
}
154+
155+
// 添加书本到书架
156+
public fun add_book(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>) {
157+
let book = Book {
158+
title: ascii::string(title),
159+
description: ascii::string(description)
160+
};
161+
162+
dynamic_field::add<vector<u8>, Book>(&mut bookshelf.id,title, book);
163+
bookshelf.book_count = bookshelf.book_count + 1;
164+
}
165+
166+
public fun add_book_obj(bookshelf: &mut Bookshelf, book: Book) {
167+
dynamic_field::add<vector<u8>, Book>(&mut bookshelf.id,
168+
book.title.into_bytes(), book);
169+
bookshelf.book_count = bookshelf.book_count + 1;
170+
}
171+
172+
// 获取书本
173+
public fun get_book(bookshelf: &Bookshelf, title: vector<u8>): &Book {
174+
dynamic_field::borrow(&bookshelf.id, title)
175+
}
176+
177+
// 设置书本的描述信息
178+
public fun set_book_desc(bookshelf: &mut Bookshelf, title: vector<u8>, description: vector<u8>) {
179+
let book_mut_ref: &mut Book = dynamic_field::borrow_mut(&mut bookshelf.id, title);
180+
book_mut_ref.description = ascii::string(description);
181+
}
182+
183+
// 判断书本是否存在
184+
public fun is_book_existed(bookshelf: &Bookshelf, title: vector<u8>): bool {
185+
dynamic_field::exists_(&bookshelf.id, title)
186+
}
187+
188+
public fun is_book_exists_with_type(bookshelf: &Bookshelf, title: vector<u8>): bool {
189+
dynamic_field::exists_with_type<vector<u8>, Book>(&bookshelf.id, title)
190+
}
191+
192+
// 从书架上移除书本
193+
public fun remove_book(bookshelf: &mut Bookshelf, title: vector<u8>): Book {
194+
bookshelf.book_count = bookshelf.book_count - 1;
195+
dynamic_field::remove<vector<u8>, Book>(&mut bookshelf.id, title)
196+
}
197+
198+
// 如果存在指定标题书本,则从书架上移除书本
199+
public fun remove_if_book_exists(bookshelf: &mut Bookshelf, title: vector<u8>): Option<Book> {
200+
bookshelf.book_count = bookshelf.book_count - 1;
201+
dynamic_field::remove_if_exists<vector<u8>, Book>(&mut bookshelf.id, title)
202+
}
203+
204+
public fun get_book_count(bookshelf: &Bookshelf): u64{
205+
bookshelf.book_count
206+
}
207+
208+
public fun get_book_title(book: &Book): String {
209+
book.title
210+
}
211+
212+
public fun get_book_desc(book: &Book): String {
213+
book.description
214+
}
215+
}
216+
```
217+
218+
## 单元测试
219+
220+
```rust
221+
#[test_only]
222+
module cookbook::dynamic_field_test {
223+
use std::ascii;
224+
use sui::test_scenario as ts;
225+
use cookbook::dynamic_field::{Bookshelf, create_bookshelf, add_book, get_book,
226+
set_book_desc, is_book_existed, is_book_exists_with_type, remove_book,
227+
get_book_count, get_book_title, get_book_desc};
228+
229+
#[test_only]
230+
use sui::test_utils::assert_eq;
231+
232+
#[test]
233+
public fun test_dynamic_field() {
234+
let alice = @0xa;
235+
236+
let mut ts = ts::begin(alice);
237+
238+
// 创建书架
239+
{
240+
create_bookshelf(ts.ctx());
241+
};
242+
243+
// 添加书本到书架
244+
let expected_title = b"Mastering Bitcoin";
245+
let expected_description= b"1st Edition";
246+
let expected_new_description= b"3rd Edition";
247+
248+
{
249+
ts.next_tx(alice);
250+
let mut bookshelf: Bookshelf = ts.take_shared();
251+
252+
add_book(
253+
&mut bookshelf,
254+
expected_title,
255+
expected_description,
256+
);
257+
258+
assert_eq(bookshelf.get_book_count(), 1);
259+
260+
ts::return_shared(bookshelf);
261+
};
262+
263+
// 获取书本
264+
{
265+
ts.next_tx(alice);
266+
let bookshelf: Bookshelf = ts.take_shared();
267+
268+
let book = get_book(
269+
&bookshelf,
270+
expected_title,
271+
);
272+
273+
assert_eq(book.get_book_title(), ascii::string(expected_title));
274+
assert_eq(book.get_book_desc(), ascii::string(expected_description));
275+
276+
ts::return_shared(bookshelf);
277+
};
278+
279+
// 设置书本的描述信息
280+
{
281+
ts.next_tx(alice);
282+
let mut bookshelf: Bookshelf = ts.take_shared();
283+
284+
set_book_desc(
285+
&mut bookshelf,
286+
expected_title,
287+
expected_new_description,
288+
);
289+
290+
let book = get_book(
291+
&bookshelf,
292+
expected_title,
293+
);
294+
295+
assert_eq(book.get_book_title(), ascii::string(expected_title));
296+
assert_eq(book.get_book_desc(), ascii::string(expected_new_description));
297+
298+
ts::return_shared(bookshelf);
299+
};
300+
301+
// 判断书本是否存在
302+
{
303+
ts.next_tx(alice);
304+
let bookshelf: Bookshelf = ts.take_shared();
305+
306+
let is_existed = is_book_existed(
307+
&bookshelf,
308+
expected_title,
309+
);
310+
assert_eq(is_existed, true);
311+
312+
let is_existed = is_book_exists_with_type(
313+
&bookshelf,
314+
expected_title,
315+
);
316+
assert_eq(is_existed, true);
317+
318+
ts::return_shared(bookshelf);
319+
};
320+
321+
// 从书架上移除书本
322+
{
323+
ts.next_tx(alice);
324+
let mut bookshelf: Bookshelf = ts.take_shared();
325+
326+
assert_eq(bookshelf.get_book_count(), 1);
327+
328+
let book = remove_book(
329+
&mut bookshelf,
330+
expected_title,
331+
);
332+
333+
assert_eq(bookshelf.get_book_count(), 0);
334+
assert_eq(book.get_book_title(), ascii::string(expected_title));
335+
assert_eq(book.get_book_desc(), ascii::string(expected_new_description));
336+
337+
bookshelf.add_book_obj(book);
338+
339+
ts::return_shared(bookshelf);
340+
};
341+
342+
ts.end();
343+
}
344+
}
345+
```
346+

0 commit comments

Comments
 (0)