Sui Move 语法和设计模式,并发布一个代币到链上。
在第一节入门 Sui Move 开发:1. 环境安装 中我们已经成功安装了 Sui Move
开发环境及开发 IDE。
在第二节# 入门 Sui Move 开发:2. 常用命令、编写并发布 Hello World 合约 中我们也了解了常用的命令并在链上发布了自己的第一个合约 hello world
。
本节介绍 Sui Move
中的基础语法,学完本节再回头看我们在 hello world
中的代码,相信你就可以很轻松的看懂了,学完本节你将学会如何在 Sui
链上发布代币。
如果你没有学过其他编程语言可以这么理解:语法就是编写代码的一些规定。
Move 是强类型语言,并且不会自动转换类型,转换类型使用 as
关键字。
数据类型包含:
true
、false
struct
关键字定义)let a: u8 = 1; // 指定 a 的类型为 u8
let c = 10; // 不指定则默认类型为 u64
let isSui = true; // isSui 是 bool 类型
let sender: address; // 定义类型为 address 的变量 sender
let sender = @0x0; // 定义 address 类型变量并设置初始值
// Hello 结构体
public struct Hello has key, store { i
d: UID,
text: String
}
使用 let
关键字定义变量,格式 let 变量名: 类型 = 赋初始值;
,变量的作用域是在它所在的大括号中。
fun dog() {
let a = 1;
}
fun cat() {
a = 2; // 这句会报错
}
使用 const
关键字定义,常量名大写。
const T:u8 = 10;
语法:if(布尔表达式) 表达式1 else 表达式2;
注意括号结尾需要分号。
let i = 10;
let mut a:u64;
// 单行不加花括号
if(i > 5) a = i + 1;
// 多行加花括号
if(i > 6) {
a = i + 2;
};
// if...else...
if(i > 3) {
a = i + 1;
} else {
a = i -1;
};
支持 while
和 loop
循环。
continue
: 跳过本次循环,进入下一个循环。
break
:跳出循环。
let mut i = 1;
// while 循环
while( i < 3) {
i = i + 1;
};
// loop 循环
loop {
if(i >= 8) {
break; // 满足条件跳出循环
};
}
语法:
<public> <entry> fun 方法名(<参数名: 参数类型>): (<返回值类型>) {
// 函数体
}
<>
表示可没有的部分
fun
同模块内可以被调用public fun
模块外可以被调用public(package) fun
可以在同包的不同模块中被调用public entry fun
可以被任意模块,被命令行,dapp 调用entry fun
可以被同模块,命令行,dapp 调用fun init() {
}
public fun add(a: u64, b: u64): u64 {
a + b
}
参数传递格式:
ref
(不可变引用,格式 & 参数类型
)只能查看参数mut ref
(可变引用,格式 &mut 参数类型
)可以查看和编辑参数value
(值引用,格式 参数类型
)可以查看、编辑、删除参数public struct Person {
name: String,
score: u128,
}
// 不可变引用:访问对象的某个字段
public fun view_person(person: &Person): String {
person.name
}
// 可变引用:编辑对象的值
public fun edit_person(person: &mut Person, newName: String) {
person.name = newName
}
// 值引用:删除对象
public fun del_person(person: Person) {
let Person {id, name: _} = person; // 解包语法
object::delete(id);
}
fun compare(a: u64, b: u64): u8 {
if(a == b) {
return 0 // 直接返回
};
// 返回值在最后一时可以省略 return
if(a > b) {
1 // 省略 return
} else {
2 // 省略 return
}
}
// 返回两个值
fun return_nums(): (u64, bool) {
(19, true)
}
fun call_return_nums(): u64 {
// 接收多个函数返回值,必须有括号
let (a, b) = return_nums();
if(b) {
a
} else {
0
}
}
一种特殊类型的函数,通常用来执行具有链上交易特性的操作,是用户通过交易调用智能合约的主要入口,用于管理状态更改(代币转账、数据更新等)和触发不同的操作。
定义要求:
entry
关键词// entry 函数,调用时不需要传入 ctx 参数值,虚拟机会提供
public entry fun mint(ctx: &mut TxContext) {
let object = Hello{
id: object::new(ctx),
text: utf8(b"Hello Sui!")
};
transfer::public_transfer(object, tx_context::sender(ctx));
}
注意:结构体不能包含自身类型
结构体命名规则:
public struct Person {
name: String,
score: u128,
}
// 实例化 Person 结构体
let p = Person { name: utf8(b"greyhao"), score: 10 };
结构体数据类型的能力,包含:key
,store
,copy
,drop
四种。使用 has
关键字来声明结构体的 albility
。
给结构体设置 store,copy,drop 时,需要确保结构体内所有字段包含这些能力。
基础数据类型和内建数据类型默认有:store、copy、drop 能力。
key
key
用来标识结构体是否是对象。对象是特殊的结构体。
public struct PersonObj has key, store {
id: UID, // key ability 要求第一个字段必须为 id: UID,反过来说有 id 说明这是个对象
name: String,
}
store
使用场景:
copy
标记结构体是否可以被复制,不能用于对象结构体。
drop
标记这个结构体是否能在作用域结束的时候自动删除。不能自动删除则需要手动删除。同样只能用于非对象结构体。
// 普通结构体
public fun drop(p: Person) {
let Person{name: _, score: _} = p;
}
// 删除对象,开发中积极删除无用对象,减少 gas 消耗
public fun drop_article(po: PersonObj) {
let PersonObj{id: id, title:_, name: _} = po;
object::delete(id); // 删除对象 id 的唯一方法
}
Capability
是用来控制和管理对特定资源或模块的访问,实现细粒度的权限管理。
public struct TeacherCap has key {
id: UID
}
// 这个函数方法使其只能被拥有 TeacherCap capability 的 object 调用
// _ 表示 TeacherCap 会被立即消耗
public entry fun create_object(_: &TeacherCap, ctx: &mut TxContext) {
//
let xx_obj = {};
transfer::transfer(xx_obj, tx_context::sender(ctx))
}
witness
是一种设计模式,用于证明有关的一个资源或类型 A
,在短暂的 witness
资源被消耗后只能启动一次。
One Time Witness(OTW)是 witness
的一个子模式,在创建同质化代币(也就是 Coin
)时会用到。
下面是创建一个代币的简单例子,如何创建合约项目以及如何发布合约可以在上一节中找到相关内容。
// 一个创建代币的简单例子
module coin_greyhao::greyhaocoin {
use sui::coin::{Self, TreasuryCap, Coin};
// 结构体的名字是模块名的大写,并且必须有 drop 能力
public struct GREYHAOCOIN has drop { }
fun init(witness: GREYHAOCOIN, ctx: &mut TxContext) {
// 代币的信息
let decimals = 8;
let symbol = b"GREYHAOCOIN";
let name = b"GHC";
let description = b"Coin was created by Greyhao.";
// 返回 treasury_cap
let (treasury_cap, metadata) = coin::create_currency(witness, decimals, symbol, name, description, option::none(), ctx);
transfer::public_freeze_object(metadata);
// treasury_cap 转给了发起交易的地址,所以 mint、burn 方法只能创建代币的地址可以调用
transfer::public_transfer(treasury_cap, tx_context::sender(ctx));
}
public entry fun mint(witness: &mut TreasuryCap<GREYHAOCOIN>, amount: u64, recipitent: address, ctx: &mut TxContext) {
coin::mint_and_transfer(witness, amount, recipitent, ctx);
}
public entry fun burn(witness: &mut TreasuryCap<GREYHAOCOIN>, coin: Coin<GREYHAOCOIN>) {
coin::burn(witness, coin);
}
}
到这里我们就介绍了 Sui Move
的一些语法并完成了发布一个代币需要的代码的编写。
你可以尝试自己发一个代币到链上,然后使用不同的地址来调用 mint
方法看看会有什么不同。
本节中有很多需要记忆的地方,多写就会变得熟练。
如果觉得本节内容对你有所帮助,可以点赞鼓励下。
如果你对文章中内容有任何疑问可以留言。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!