{"content":{"title":"MOVE入门|第二节：move学习之模块及脚本","body":"Move开发的程序有 Modules（模块） 和 Scripts（脚本）两种类型：模块是定义结构类型以及对这些类型进行操作的函数的库。结构类型定义Move全局存储的模式，模块函数定义了更新存储的规则。模块本身也存储在全局存储中。脚本是类似于传统语言中main函数，是执行程序的入口点。脚本通常调用已发布模块的函数来更新全局存储，且脚本不会发布到全局存储中。\r\n\r\n# 模块(Module)\r\nModules（模块）定义了结构体以及一组对结构体操作的函数。结构体主要用于定义全局存储的资源，而函数定义的是更新资源的规则。\r\n有点像面向对象编程语言中类的概念，如在move中可以定义一个名为Math的模块（类），在其中定义加减乘除等函数（类中的方法）来完成这些运算。\r\n## 语法\r\n```move=\r\nmodule <address>::<identifier> {\r\n\r\n    (<use> | <friend> | <type> | <function> | <constant>)*\r\n}\r\n```\r\n- ```module <address>::<identifier>```:module为模块声明关键字，\r\n```<address>```为模块发布在全局存储上的地址，可以是命名地址或文字地址\r\n```<identifier>```为模块名\r\n- ```<use>```:可以使用use关键字导入需要的模块\r\n- ```<constant>```:在module中可以使用const关键字声明常量\r\n- ```<function> ```:可以定义函数\r\n- ```<type> ```:指在module中可以定义结构体\r\n- ``` <friend>```:指可以使用friend关键字在moudle中指定一个可信模块列表\r\n\r\n\r\n\r\n## 例子\r\n```move=\r\nmodule 0x01::Test{\r\n    struct Example has copy,drop {i:u64}\r\n\r\n    use std::debug;\r\n\r\n    const ONE :u64 =1;\r\n\r\n    public fun print(x:u64){\r\n        let sum =x+ONE;\r\n        let example = Example{i:sum};\r\n        debug::print(&example);\r\n    }\r\n}\r\n```\r\n下面详细解释一下以上代码：\r\n- ```struct Example has copy,drop {i:u64}```:定义了一个结构体Example，有copy和drop的能力（能力我们在后面章节会具体介绍），结构体中定义了一个u64变量i。\r\n- ```module 0x01::Test``` ：指模块 Test 会通过 publish 发布到全局存储中地址0x01下。所以可以使用0x01::Test::函数名这种形式进行调用\r\n- ```use std::debug```:使用use关键字导入debug模块。std为标准库地址，他也是一个命名地址（即对数值地址命名）。\r\n- ```const ONE :u64 =1```:使用const关键字声明一个常量ONE\r\n- ```public fun print(x:u64)```:定义了一个打印函数\r\n- ```let example = Example{i:sum}```：实例了一个结构体变量example。\r\n- ```debug::print(&example)```:调用debug模块下的print函数来打印example的值\r\n\r\n\r\n**注意：发布模块不会执行任何函数。要使用模块就得使用脚本。**\r\n\r\n此时我们先编译发布一下模块\r\n\r\n```htmlmixed=\r\n1.move build编译sources下的move代码\r\nmove build \r\n2.在沙盒环境使用move sandbox publish -v发布字节码到0x01名下。\r\nmove sandbox publish -v \r\n3.检查0x01地址下是否保存Test模块。\r\nls storage/0x00000000000000000000000000000001/modules |grep Test\r\n```\r\n\r\n![upload_1.png](https://img.learnblockchain.cn/attachments/2023/01/a6utdF4s63c69655d5698.png)\r\n如果想要使用此模块中的函数，可以使用脚本调用，也可以使用单元测试来测试。这里我们先介绍使用脚本调用\r\n```move=\r\nscript {\r\n\r\n//引入Test模块\r\nuse 0x1::Test;\r\n\r\nfun test_T(i:u64){\r\n\r\n//调用Test模块中的print函数\r\n    Test::print(i);\r\n    }\r\n}\r\n```\r\n运行脚本：\r\n```move=\r\nmove sandbox run sources/scripts/test_script.move --args 1 \r\n```\r\n\r\n![upload_779b70a73a88c59e6c9c48d7475ee047.png](https://img.learnblockchain.cn/attachments/2023/01/2ZcMKrY363c696651c75e.png)\r\n\r\n\r\n# 脚本（script）\r\n在move中，Script是链下执行程序的入口点，不需要部署到链上，主要用于调用模块中函数去更新资源。\r\n\r\n**注意：一个脚本文件中有且只能有一个函数，函数名可以任意起。**\r\n\r\n## 语法\r\nscript文件中，通常包括：\r\n- use声明：声明需要引入的模块。语法为：```use 模块发布地址::模块名```\r\n- 常量：script中可以包含常量。语法为：```const 常量名:类型 = 常量的值```\r\n- 主函数：script中唯一的函数，可以有任意数量的参数，**但不能有返回值**。\r\n\r\n```move=\r\nscript {\r\n//1.使用use来引入需要使用的模块\r\n    <use>*\r\n//2.常量\r\n    <constants>*\r\n//3.主函数\r\n    fun <identifier><[type parameters: constraint]*>([identifier: type]*) <function_body>\r\n}\r\n```\r\n\r\n## 例子\r\n```move=\r\nscript{\r\n    //导入标准库中的debug模块 （语法：use address::模块名）\r\n    use std::debug;\r\n\r\n//声明常量ONE\r\n    const ONE:u64 =1;\r\n\r\n//主函数\r\n    fun main(x:u64){\r\n    //声明一个变量sum，值为x+ONE\r\n        let sum =x +ONE;\r\n    //调用debug模块的print函数，打印出sum的值\r\n        debug::print(&sum);\r\n    }\r\n\r\n}\r\n```\r\n沙盒环境执行script脚本\r\n\r\n通过使用--args向脚本main函数传参\r\n```move=\r\nmove sandbox run sources/scripts/test_script.move --args 1 \r\n```\r\n\r\n\r\n![upload_bdacf258caf1851dee15e983802b6a59.png](https://img.learnblockchain.cn/attachments/2023/01/fY37jto463c696754264d.png)\r\n\r\n\r\n# 总结\r\n这一讲介绍了模块与脚本，模块是发布代码供他人访问的唯一方法，而发布模块不会执行任何函数，要使用模块就得使用脚本，即调用关系为：user->script->module。"},"author":{"user":"https://learnblockchain.cn/people/12519","address":null},"history":"QmT8uCMyp4d2k3WVNHSveDXWE6W4jhj54jt9UsWKJc8omX","timestamp":1673970445,"version":1}