跳转至

Move语言笔记

快速创建一个 Sui package 框架⚓︎

sui move new <PACKAGE NAME>
这条指令创建了:

  • 项目根文件夹 hello_world
  • Move.toml 配置文件
  • 用于存放 Sui Move 智能合约的 sources 子文件夹

Move.toml 包含三个部分:

  • [package] 声明了该 package 的命名和版本数
  • [dependencies] 声明了该 package 依赖的其他 packages, 包括 Sui 标准库和其他第三方依赖库
  • [addresses] 声明了该 packages 源代码中地址的别名

基本数据类型⚓︎

Integers (u8, u64, u128), boolean and address.
即整型、布尔型、地址型。

Integer types 整数类型⚓︎

  • u8 表示一个无符号的 8 位整数,也就是一个字节。
  • u64 表示一个无符号的 64 位整数,也就是 8 字节。
  • u128 表示一个无符号的 128 位整数,也就是 16 字节。

这些类型后面的数字表示整数分配的内存空间的大小。所以,u8 表示的是 1 个字节的内存空间大小,u64 表示的是 8 个字节的内存空间大小,而 u128 表示的是 16 个字节的内存空间大小。
定义方式:
image.png

Boolean 布尔类型⚓︎

false and true
一些定义方式:
image.png

Address 地址⚓︎

地址是区块链中发送者(或钱包)的标识符。需要地址类型的最基本的操作是发送硬币和导入模块(module)。
image.png

数值比较⚓︎

使用运算符 as 将整数变量转换为另一个大小:
image.png
同等大小类型的整数才可以比较

注释⚓︎

语法和C一样,但不能使用utf-8(就是注释不能写汉字)

初始化变量⚓︎

使用 let 在当前范围内创建新变量,并选择性地使用 value 初始化此变量
let <VARIABLE> : <TYPE>;or let <VARIABLE> = <EXPRESSION>
image.png

下划线——未使用⚓︎

在 Move 中,必须使用每个变量(否则您的代码将无法编译),因此您不能初始化一个变量并保持其不变。虽然您有一种方法可以将变量标记为故意未使用 - 通过使用下划线 _
image.png
Move 允许您定义相同的变量两次,但有一个限制 - 它仍然需要使用。

块表达式与作用域⚓︎

块是一个表达式;它标有大括号 - {} 。块可以包含其他表达式(和其他块)。
在定义块时,您实际上定义了一个范围。
image.png

变量的生命周期⚓︎

变量仅存在于定义它的作用域(或块)内。当其作用域结束时,变量将死亡。

块返回值⚓︎

作用域中的最后一个表达式(不带分号)是此作用域的返回值。
image.png

控制流⚓︎

if表达式⚓︎

if (<bool_expression>) <expression> else <expression>;
image.png

  • 分支兼容性:两个分支必须返回兼容(相同)类型
  • if 可以单独使用 - 没有 else
  • 没有else 分支的表达式不能用于赋值

条件while循环⚓︎

while (<bool_expression>) <expression>;

  • while 不能返回值

无限loop循环⚓︎

无限循环是用关键字loop定义的。
image.png

break与continue⚓︎

关于分号。如果 break 和 continue 是块中的最后一个关键字,则不能在它们后面加上分号,因为 after 之后的任何代码都不会被执行。
image.png

有条件的中止abort⚓︎

关键字 abort允许您中止执行,并在其后放置错误代码。
image.png

assert条件中止⚓︎

内置 assert!(<bool expression>, <code>) 方法已经包装了 abort + 条件,并且可以在代码中的任何位置访问。左边的条件必须为真,否则执行右边。
assert() 当不满足条件时将中止执行,或者在相反的情况下将不执行任何操作。
image.png

  • 错误码赋值:const ENotIntendedAddress: u64 = 1;

模块module⚓︎

模块以 module 关键字开头,后跟模块名称和大括号 - 其中放置了模块内容。
默认情况下,您的模块将从您的地址编译和发布。但是,如果您需要在本地使用某些模块(例如用于测试或开发)或想在模块文件中指定您的地址,请使用 address <ADDR> {}语法
image.png

导入模块或标准库⚓︎

  • 您可以直接在代码中按模块的地址使用模块:

image.png
在此示例中,我们从地址0x1(标准库)导入了模块Offer 并使用了它的方法

  • 关键字导入

use <Address/Alias>::<ModuleName>;
<Address> 是发布者的地址,也是 <ModuleName> 模块的名称。

  • 成员导入:可以扩展 import 语句 - 您可以指定要导入的模块的哪些成员:image.png
  • 用于Self将模块与其成员一起导入image.png
  • 使用关键字 as 更改导入模块的名称。 use <Address>::<ModuleName> as <Alias>;

常量⚓︎

您可以定义模块级或脚本级常量。一旦定义,常量就无法更改。

函数⚓︎

  • 函数参数

定制类型⚓︎

Structure 使用关键词 struct 声明。一个 structure 最多拥有 4 项能力。
四类能力特性:

  • Copy: 值可以被复制
  • Drop: 在作用域范围结束后值可以被丢弃
  • Key: 在全局存储操作中值可以被用为key键
  • Store: 值可以在全局存储中被存储

函数可见性⚓︎

  • private: 作为函数可见性的默认设置;只允许同一 module 内的函数获取
  • public: 该函数既可以被同一 module 内的函数获取,也可以被其他 module 定义的函数获取
  • public(friend): 该函数既可以被同一 module 内的函数获取,同时也可以被该 module 的 friends 清单上包含的 module 所定义的函数获取。

Entry 函数⚓︎

在 Sui Move 中,entry 函数可以被交易 transactions 直接调用。它们需要满足下面三个条件:

  • 被关键词 entry 标注
  • 没有返回值
  • (可选) 最后一个参数是 TxContext 类型实例的可变引用

部署智能合约⚓︎

sui client publish --path <absolute local path to the Sui Move package> --gas-budget 100000000(要是提示gas不够就多加几个0)

  • 获取测试币

Win:(Powershell中执行)

PowerShell
1
2
3
4
5
6
7
8
9
$body = @{
    FixedAmountRequest = @{
        recipient = '钱包地址'
    }
} | ConvertTo-Json

Invoke-WebRequest -Uri 'https://faucet.devnet.sui.io/gas' -Method POST -Body $body -Headers @{
    'Content-Type' = 'application/json'
}
Linux:
PowerShell
1
curl --location --request POST 'https://faucet.devnet.sui.io/gas' --header 'Content-Type: application/json' --data-raw '{ "FixedAmountRequest": { "recipient": "替换为你的钱包地址" } }'

  • 跳过版本检查:--skip-fetch-latest-git-deps
  • 跳过依赖性检查:--skip-dependency-verification

image.png

  • 输出中文

image.png

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
module hello::hello{
    use std::string;
    use sui::object::{Self, UID};
    use sui::transfer;
    use sui::tx_context::{Self, TxContext};

        ///include any string object
    struct HelloWorldObject has key, store {
        id: UID,
        /// strings included by object 
        text: string::String
    }

    public entry fun mint(text: vector<u8>,ctx: &mut TxContext){
        let object = HelloWorldObject{
            id: object::new(ctx),
            text: string::utf8(text)
        };
        transfer::transfer(object, tx_context::sender(ctx));
    }
}
使用vector来定义字符串变量
再次发布智能合约
sui client publish --gas-budget 100000000 --skip-fetch-latest-git-deps --skip-dependency-verification
image.png
调用函数,传入参数args
sui client call --function mint --module hello --package 0x0379266c1b772298bd93d0da5f8f684f30f9c5eb2be5af36d9f06f5ee7c47179 --args "你好,世界" --gas-budget 10000000
image.png
在sui explorer上查看相关信息,输入 Transaction Effects 下的 Created Objects ID
image.png
可以看到text信息

Sui Objects 所有权⚓︎

在 Sui Move 中总共有四种类型的所有权。

  • 被拥有
  • 被一个地址拥有
  • 被另一个 object 拥有
  • 共享
  • 不可变的共享
  • 可变的共享

被拥有的 Objects⚓︎

  • 被一个地址拥有:使用transfer方法将一个object转移到一个地址

(transfer的函数方法调用会完全消耗掉object,即transfer之后object在当前交易中是不能再次被获取的)
之后对object的读写操作都必须由object所有者发起交易
use sui::transfer
transfer::transfer(obj, recipient);

被另一object拥有的object(子object)⚓︎

使用dynamic_object_field方法创建的object

不可变的共享object(不能被修改和删除,也不能解冻)⚓︎

transfer::freeze_object(obj);

可变的共享object⚓︎

可被任何人读写
transfer::share_object(obj);

参数传递与删除Object⚓︎

image.png

结构体嵌套(Object Wrapping)⚓︎

image.pngimage.png
实现成绩单信息的请求和解包
image.png

用与权限管理的Capability模式⚓︎

把带有管理员权限的能力也设计成一个Object并赋予给特定账户,同时限定需要管理员运行的函数方法
image.png
增加传入的参数TeacherCap,并用下划线将它标注为未使用的变量或参数
image.png
添加管理员
image.png

日志(Events)⚓︎

要引用use sui::event;
image.png
在函数中添加发送events信息

泛型⚓︎

泛型是具体类型或其他属性的抽象替代品