# Move简明教程(2)【模块与脚本】

By [自如](https://paragraph.com/@0xb68b9afccf6cc50608d064f61101e689c2273e05) · 2022-08-16

---

       Move 有两种不同类型的程序: 模块和脚本。模块是定义结构类型以及操作这些类型的函数的库。结构类型定义 Move 的全局存储模式，模块函数定义更新存储的规则。模块本身也存储在全局存储中。脚本是类似于传统语言中的主函数的可执行入口点。脚本通常调用已发布模块的函数对全局存储进行更新。脚本是不在全局存储中发布的临时代码段。
    
       Move的源文件(或编译单元)可能包含多个模块和脚本。但是，发布模块或执行脚本是独立的 VM 操作。
    

一、脚本     脚本具有如下结构：

    script {
        <use>*
        <constants>*
        fun <identifier><[type parameters: constraint]*>([identifier: type]*) <function_body>
    }
    

脚本块必须以它的所有 use 声明开始，然后是任何常量和(最后)主函数声明。Main 函数可以有任何名称(也就是说，它不需要被称为 main) ，是脚本块中唯一的函数，可以有任意数量的参数，并且不能有返回值。下面是每个组件的示例:

    script {
        // Import the Debug module published at the named account address Std.
        use Std::Debug;
        const ONE: u64 = 1;
        fun main(x: u64) {
            let sum = x + ONE;
            Debug::print(&sum)
        }
    

脚本的能力非常有限ーー它们不能声明好友(Friends)、结构类型或访问全局存储。它们的主要用途是调用模块函数。

二、 模块     模块具有以下语法：

    module <address>::<identifier> {
        (<use> | <friend> | <type> | <function> | <constant>)*
    }
    

其中 < address > 是有效的命名地址或文字地址。例如：

    module 0x42::Test {
        struct Example has copy, drop { i: u64 }
        use Std::Debug;
        friend 0x42::AnotherTest;
        const ONE: u64 = 1;
    
        public fun print(x: u64) {
            let sum = x + ONE;
            let example = Example { i: sum };
            Debug::print(&sum)
        }
    }
    

"module 0x42::Test"部分表示模块 Test 将在全局存储中的账户地址0x42下发布。模块也可以使用命名地址声明。例如:

    module TestAddr::Test {
        struct Example has copy, drop { a: address}
        use Std::Debug;
        friend TestAddr::AnotherTest;
    
        public fun print() {
            let example = Example { a: @TestAddr};
            Debug::print(&example)
        }
    }
    

因为命名地址只存在于源语言级别和编译期间，所以在字节码级别，命名地址将完全被它们所代表的值所取代。例如，如果我们有以下代码:

    script {
        fun example() {
            MyAddr::M::foo(@MyAddr);
        }
    }
    

然后我们将 MyAddr 设置为0xC0FFEE，那么它将等效于下面的操作:

    script {
        fun example() {
            0xC0FFEE::M::foo(@0xC0FFEE);
        }
    }
    

但是在源代码级别，这两个函数是不等价的ーー函数 M: : foo 必须通过 MyAddr 命名的地址来访问，而不是通过分配给该地址的数值来访问。模块名称可以以字母 a 到 z 或字母 A 到 Z 开头。在第一个字符之后，模块名称可以包含下划线 \_、字母 a 到 z、字母 A 到 Z 或数字0到9。

    module my_module {}
    module FooBar42 {}
    

      通常，模块名称以大写字母开头。一个名为 MyModule 的模块应该存储在一个名为 MyModule.move 的源文件中。     
    
       模块块内的所有元素可以以任意顺序出现。基本上，模块是类型和函数的集合。Uses关键字可以声明来自其他模块的导入类型，使用Friends可以指定受信任模块的列表，Constants可以定义该模块函数中使用的私有常量。
    

原文：[https://mp.weixin.qq.com/s/GJM31htRrCFvcLOTPrHasA](https://links.jianshu.com/go?to=https%3A%2F%2Fmp.weixin.qq.com%2Fs%2FGJM31htRrCFvcLOTPrHasA)

---

*Originally published on [自如](https://paragraph.com/@0xb68b9afccf6cc50608d064f61101e689c2273e05/move-2)*
