以Hello World程序为例,来熟悉Aptos工程中的基本概念。
在上篇文章里,我们一起搭建了Aptos开发环境,并且成功运行了Hello World程序。接下来,我将以Hello World程序为例。一起来熟悉Aptos工程中的基本概念。
Aptos工程项目拆解、Move语法、Cargo包管理工具、测试用例
接下来,我会使用上图中的Move.toml和HelloAptos.move文件来进行讲解。
Aptos项目的包管理工具使用的是Cargo。Cargo的作用和Python的pip,Nodejs的npm类似。
在Move.toml文件中,依赖包的来源有很多种,例如crates.io、git仓库、本地库文件等等。自然而然,不同的来源应当有不同的书写方式。
通常情况下,我们使用以下两种的方式来设置依赖包,基本上就能满足绝大多数的场景需求。
[dependencies]
time = "0.1.12"
只需要名称和版本字符串。默认情况下,Cargo是准备在crates.io上查找依赖项。
rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
由于我们尚未指定任何其他信息,因此 Cargo 假定我们打算使用最新的提交master分支来构建。
rand = { git = "https://github.com/rust-lang-nursery/rand", branch = "next" }
我们指定了next分支,那么Cargo就会拉取next分支的包。除此之外,你还可以将git字段和rev、tag还有branch这些用于指定其他内容的字段搭配起来使用。
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "devnet" }
我们指定了subdir文件夹和devnet分支,然后Cargo将拉取git路径的subdir文件夹下的devnet分支来构建我们的程序。
至此,除了这两种常用的引包方式外,更多关于Cargo设置依赖的方法,这里就不再罗列赘述了,需要查看的请移步查看。
http://llever.com/cargo-book-zh/reference/manifest.zh.html#dependency-sections
Move语法这里不做罗列赘述。只把我认为使用频率较高的先列出来,其余语法遇到再学不迟。
基本的数据类型里没有浮点型,那么小数计算如何处理呢?
Solidity中通过单位的不同处理小数,10^18 wei=1 ether,并且Solidity有SafeMath这样的lib可供加减乘除使用。
那Aptos呢?在Aptos里,你可以把Solidity的Safemath用Move重写一遍,或者使用Sui已封装好的lib。这个在后续的文章中再进行研究。
传统资产合约编程,最大也是最多的安全问题就是:类型溢出。Move的一个大特色,就是用Resource类型来解决这一程序员编程遇到的bug问题。
Resource数据类型,是一种特殊的结构体类型。Resource只能用struct进行定义,同时必须使用key这个abilitities。换言之,只有key,store能力,没有drop,copy的就是resource。
对resource的增删改查需要通过特殊的函数进行包裹后进行调用,特殊的函数是指的borrow_global和borrow_global_mut。
//Resouce是一种特殊的结构体类型。Resource只能用struct关键字定义,同时必须拥有key、store这两种abilitities。
//例如HelloAptos.move中的Message
struct Message has key{
msg:string::String,
message_change_events: event::EventHandle<MessageEvent>,
}
这里的Message就是合约的resource。简单点理解,resource就像一个保险箱,你只能用你自己的账号打开并且操作保险箱里面的内容。你能做的操作只是对属于你的资源(resource)进行增删改查。
//移动resource到account需要使用内置函数move_to()。第一个参数
native fun move_to<T: key>(account: &signer, value: T);
move_to(account, Message { msg:message, message_change_events: event::new_event_handle<MessageEvent>(account), });
- 删除元素
move_to(account, Message { msg:message, message_change_events: event::new_event_handle<MessageEvent>(account), });
- 修改元素
//可变引用(&mut): 可变引用赋予我们读取和更改值的能力。 //native fun borrow_global_mut<T: key>(addr: address): &mut T; let old_message = borrow_global_mut<Message>(account_addr); //修改resource中的内容 old_message.msg = message;
- 查询元素
//全局函数 borrow_global 返回了对 Resource T 的不可变引用。不可变的引用(&)允许我们在不更改值的情况下读取值。其签名如下: //native fun borrow_global<T: key>(addr: address): &T;
*&borrow_global<Message>(addr).msg
//全局函数 borrow_global_mut 返回了对 Resource T 的可变引用可变引用(&mut)赋予我们读取和更改值的能力。 //native fun borrow_global_mut<T: key>(addr: address): &mut T;
- 检查资源
exists<Message>(account_addr)
### 自定义数据类型
- struct
struct的定义方式和C语言的的很类似。
### 打印日志
- debug::print()
debug::print(&account_addr);//打印账户地址 debug::print(&1234); //打印1234
需要注意的是,目前move的debug和assert功能都不完善,传参都是用引用。
## 测试用例
public entry fun sender_can_set_message(account: signer) acquires Message { let addr = signer::address_of(&account); say_message(&account, b"Hello, Aptos"); debug::print(&account); debug::print(&3456); //无法打印字符串,因为move没有string类型 //let log : string::String = b"hello world!"; //debug::print(&log); assert!( get_message(addr) == string::utf8(b"Hello, Aptos"), ENO_MESSAGE ); }
在HelloAptos.move中编写好测试用例后,控制台输入`sudo aptos move test`。在控制台可以看到debug的日志。
Running Move unit tests [debug] 0000000000000000000000000000000000000000000000000000000000000001 [debug] (&) { 0000000000000000000000000000000000000000000000000000000000000001 } [debug] 3456 [ PASS ] 0xfbd4140a63e8fe7d6e9e25aff78e11876b1b6c21bc8d34b51cbfff40ca03164b::Message::sender_can_set_message Test result: OK. Total tests: 1; passed: 1; failed: 0 { "Result": "Success" }
今天就先讲解到这儿,因为Resource是Move里很重要的数据类型,是它让Move变得独一无二,安全且强大。所以在接下来的文章里,咱们一起动手操作Resource,加深我们对Resource的认识。
### 参考文档
- https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/deps/move-stdlib/sources/fixed_point32.move
- http://llever.com/cargo-book-zh/reference/manifest.zh.html#dependency-sections
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!