当前位置: 首页 > article >正文

sui move笔记

前言

一些疑问:

  • sui 和move是什么关系?

基础

基本数据类型

Move 的基本数据类型包括: 整型 (u8, u32,u64, u128,u258)、布尔型 boolean 和地址 address。

Move 不支持字符串和浮点数。

_u8:代表8位无符号整数类型,范围是0~255。占用内存8位
_u16:代表16位无符号整数类型,范围是0~65535。占用内存16位
_u32:代表32位无符号整数类型,范围是0~4294967295。占用内存32位
_u64:代表64位无符号整数类型,范围是0~18446744073709551615。占用内64位
以此类推

整型

module ch02::int {
    fun main() {
        // define empty variable, set value later
        let a: u8;
        a = 10;

        let a = 1u32;

        // define variable, set type
        let a: u64 = 10;

        // finally simple assignment
        let a = 10;

        // simple assignment with defined value type
        let a = 10u64;

        // in function calls or expressions you can use ints as constant values
        if (a < 10) {};

        // or like this, with type
        if (a < 10u64) {}; // usually you don't need to specify type

        let b = 1u256;

        // or like this, with type
        if (b < 10u256) {}; // usually you don't need to specify type
    }
}

let a = 10 默认不手动标记类型的整型是 u64 类型,也就是等同于 let a:u64 = 10 或者 let a = 10u64

布尔型

布尔类型就像编程语言那样,包含false和true两个值。

module book::boolean {
    fun main() {
        // these are all the ways to do it
        let b : bool; b = true;
        let b : bool = true;
        let b = true;
        let b = false; // here's an example with false
    }
}

地址

地址是区块链中交易发送者的标识符,转账和导入模块这些基本操作都离不开地址。

module book::addr {
    fun main() {
        let addr: address; // type identifier

        addr = @ch02;
    }
}

模块

模块是发布在特定地址下的打包在一起的一组函数和结构体。
模块以module关键字开头,后面跟随地址::模块名称和大括号,大括号中放置模块内容。

module book::math {
    public fun sum(a: u64, b: u64): u64 {
        a + b
    }
}

注意:

  • 模块在发布者的地址下发布。标准库在 0x1 地址下发布。
  • 发布模块时,不会执行任何函数。要使用模块就得使用脚本。
  • 模块名推荐使用小写
  • 模块是发布代码供他人访问的唯一方法。新的类型和 Resource 也只能在模块中定义。默认情况下,模块将在发布者的地址下进行编译和发布

导入

Move 在默认上下文中只能使用基本类型,也就是整型、布尔型和地址,可以执行的有意义或有用的操作也就是操作这些基本类型,或者基于基本类型定义新的类型。

除此之外还可以导入已发布的模块(或标准库)。

  • 直接导入
module book::m {
    fun main(a: u8) {
        std::debug::print(&a);
    }
}

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

use关键字

要使代码更简洁(注意,0x1 是特殊的地址,实际地址是很长的),可以使用关键字use:

use <address>::<ModuleName>;

这里 </address/> 是模块发布object的地址, 是模块的名字。非常简单,例如,我们可以像下面这样从 0x1 地址导入 vector 模块。

use 0x1::vector;
  • 访问模块的内容

要访问导入的模块的方法(或类型),需要使用::符号。非常简单,模块中定义的所有公开成员都可以通过双冒号进行访问。

module book::m_use {
    use  std::debug::print;
    fun main(a: u8) {
        print(&a);
    }
}

在模块中导入
在模块中导入模块必须在 module {} 块内进行:

module book::math {
    use std::vector;
    // you are free to import any number of modules
    public fun empty_vec(): vector<u64> {
        let v = vector::empty<u64>();
        v
    }
}

成员导入
导入语句还可以进一步被扩展,可以直接导入模块的成员:

module book::m_use2 {
    // single member import
    use sui::tx_context::TxContext;
    use sui::tx_context::sender;

    // multi member import (mind braces)
    use std::vector::{
        empty,
        push_back
    };

    fun main(ctx: &mut TxContext) {
        // use functions without module access
        let vec = empty<u8>();
        push_back(&mut vec, 10);
        let _ = sender(ctx);
    }
}

使用 Self 来同时导入模块和模块成员
导入语句还可以进一步扩展,通过使用 Self 来同时导入模块和模块成员,这里 Self 代表模块自己。

module book::m_self {

    use 0x1::vector::{
    Self, // Self == Imported module
    empty
    };

    fun main() {
        // `empty` imported as `empty`
        let vec = empty<u8>();
        // Self means vector
        vector::push_back(&mut vec, 10);
    }
}

使用 use as
当两个或多个模块具有相同的名称时,可以使用关键字as更改导入的模块的名称,这样可以在解决命名冲突的同时缩短代码长度。

语法:

use <address>::<ModuleName> as <Alias>;
module ch04::m_as1 {
    use 0x1::vector::{
    Self as v,
    empty as empty_vec
    };

    fun main() {
        // `empty` imported as `empty_vec`
        let vec = empty_vec<u8>();

        // Self as V = vector
        v::push_back(&mut vec, 10);
    }
}

函数

Move 中代码的执行是通过调用函数实现的。函数以 fun 关键字开头,后跟函数名称、扩在括号中的参数,以及扩在花括号中的函数体。

module book::f01 {
    fun function_name(arg1: u64, arg2: bool): u64 {
        // function body
        10
    }
}

  • 注意:Move 函数使用snake_case命名规则,也就是小写字母以及下划线作为单词分隔符。

返回值:

module book::math {
    fun zero(): u8 {
        0
    }
}

第一步:我们定义一个 math 模块,它有一个函数:zero(),该函数返回 u8 类型的值 0。0 之后没有分号,因为它是函数的返回值

return关键字:

module book::m {
    public fun conditional_return(a: u8): bool {
        if (a == 10) {
            return true // semi is not put!
        };

        if (a < 10) {
            true
        } else {
            false
        }
    }
}

多个返回值及解构:

要指定多个返回值,需要使用括号:

module book::math {
    // ...
    public fun max(a: u8, b: u8): (u8, bool) {
        if (a > b) {
            (a, false)
        } else if (a < b) {
            (b, false)
        } else {
            (a, true)
        }
    }
}

在另一个模块中使用该函数的返回值。

module book::math_use {
    use book::math::sum;
    use book::math::max;
    fun use_max(){
        let (a,b)= max(1u8,2u8);
    }
}

上面例子中,我们解构了一个二元组,用函数 max 的返回值创建了两个新变量。

公有、私有方法、friend方法、native本地方法:

默认情况下,模块中定义的每个函数都是私有的,无法在其它模块或脚本中访问。可能你已经注意到了,我们在 Math 模块中定义的某些函数前有关键字 public:

  • 关键字 public 将更改函数的默认可见性并使其公开,即可以从外部访问。
  • 默认情况下函数是私有函数只能在定义它们的模块中访问。
  • 私有函数只能在定义它们的模块中访问。
module book::math {
    public fun sum(a: u64, b: u64): u64 {
        a + b
    }

    fun zero(): u8 {
        0
    }
}

friend 方法:
friend 方法可以指定指定的模板能调用,目前只能在同一个包内生效

module book::friends {
    friend book::m;

    public(friend) fun a_less_10(a: u8): bool {
        if(a < 10u) return true;
        false
    }
}

本地方法:
有一种特殊的函数叫做"本地方法"。本地方法实现的功能超出了 Move 的能力,它可以提供了额外的功能。本地方法由 VM 本身定义,并且在不同的VM实现中可能会有所不同。这意味着它们没有用 Move 语法实现,没有函数体,直接以分号结尾。关键字 native 用于标记本地函数,它和函数可见性修饰符不冲突,native 和 public 可以同时使用。

module book::m {
    native public fun borrow_address(s: &signer): &address;
    // ... some other functions ...
}

运算符

as

as 在move 中有两个用法:
1.给包取别名

module book::m_as1 {
    use 0x1::vector::{
        Self as v,
        empty as empty_vec
    };

    fun main() {
        // `empty` imported as `empty_vec`
        let vec = empty_vec<u8>();

        // Self as V = vector
        v::push_back(&mut vec, 10);
    }
}

2.整型类型转换 语法 (整型A as 整型 B) 当需要比较值的大小或者当函数需要输入不同大小的整型参数时,你可以使用as运算符将一种整型转换成另外一种整型 注意就是括号是一定不能省的

module book::op_as {
    fun main(){
        let _a:u64 = (10u8 as u64);
        let _b:u8 = (a as u8);
    }
}

+ - * /

注意:

  • 负数做减法一定要检查是否产生负数
  • 做加法乘法注意 溢出报错
  • 除法小心精度丢失问题
  • 得益于Move的安全设计,溢出和负数不会让合约产生安全问题,因为程序会终止运行,但是程序终止会给用户带来不好的体验,代码不是很好调试,建议还是做好溢出边界判断
module book::op_arith {

    fun main(){
        let _add_op = 1 + 1;
        let _mut_op = 1*1;
        let _minu_op = 100 -1;
        let _div_op = 100/1;
    }

}

常量

Move 支持模块级常量。常量一旦定义,就无法更改,所以可以使用常量为特定模块或脚本定义一些不变量,例如角色、标识符等。

常量可以定义为基本类型(比如整数,布尔值和地址),也可以定义为数组。我们可以通过名称访问常量,但是要注意,常量对于定义它们的模块来说是本地可见的。

module book::consts {

    use std::debug;

    const RECEIVER: address = 0x999;

    const ErrO1: u64 = 1000

    fun main(account: &signer) {
        debug::print<address>(&RECEIVER);

        let _ = RECEIVER;

        let _ = ErrO1;
    }
}

注意:

  • 一旦定义,常量是不可更改的。
  • 常量在模块是本地可见的,不能在外部使用。
  • 可以将常量定义为一个表达式(带有花括号),但是此表达式的语法非常有限。

表达式和作用域


http://www.kler.cn/a/229362.html

相关文章:

  • mysql-5.7.18保姆级详细安装教程
  • C语言:-三子棋游戏代码:分支-循环-数组-函数集合
  • 活动预告 | CCF开源发展委员会开源供应链安全技术研讨会(2025第一期)——“大模型时代的开源供应链安全风控技术”...
  • 存储过程和触发器
  • vue3 uniapp封装一个瀑布流组件
  • 基于ESP8266 wifimanager实现WiFi配置及天气显示
  • 总是提示安装不了tensorflow
  • 网络编程面试系列-02
  • 【方法论】费曼学习方法
  • IT行业证书的获取与价值:提升职业竞争力的关键
  • Django部署到服务器后无法获取到静态元素 The requested resource was not found on this server
  • C语言贪吃蛇详解
  • 软件系统架构的演变历史介绍
  • Windows显示空的可移动磁盘的解决方案
  • LeetCode、216. 组合总和 III【中等,组合型枚举】
  • block任务块、rescue和always、loop循环、role角色概述、role角色应用、ansible-vault、sudo提权、特殊的主机清单变量
  • 「深度学习」门控循环单元GRU
  • 070:vue+cesium: 利用canvas设置线性渐变色材质
  • 【Rust】——rust前言与安装rust
  • [晓理紫]每日论文分享(有中文摘要,源码或项目地址)
  • thinkphp6入门(19)-- 中间件向控制器传参
  • 鸿蒙 WiFi 扫描流程(2)
  • 《爬虫职海录》卷二 • 爬在广州
  • 2024.1.26力扣每日一题——边权重均等查询
  • 游戏后端如何实现服务器之间的负载均衡?
  • MySQL-运维篇-日志