Skip to content
🎉 Welcome to the new Aptos Docs! Click here to submit an issue.
构建Smart Contracts (Move)Move Book | Move 书籍Modules and Scripts | 模块与脚本

模块与脚本

Move 有两种不同类型的程序:模块脚本。模块是定义了结构体类型及操作这些类型函数的库。结构体类型定义了Move global storage 的架构,模块函数则定义了更新存储的规则。模块本身也存储在全局存储中。脚本是可执行的入口点,类似于传统语言中的 main 函数。脚本通常调用已发布模块中的函数来更新全局存储。脚本是临时性的代码片段,不会被发布到全局存储中。

一个Move源文件( 或 编译单元 )可以包含多个模块和脚本。但发布模块和执行脚本是虚拟机中两个独立操作。

语法

脚本

学习如何发布和执行Move脚本,请参考 Move Scripts 示例。

脚本的基本结构如下:

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

script 代码块必须首先声明所有 use 语句,接着是任何 constants 声明,最后是主 function 声明。

主函数可以任意命名(不必叫 main ),是脚本块中唯一的函数,可以接受任意数量的参数,且不能有返回值。以下是一个包含所有组件的示例:

script {
    // 导入发布在命名地址 std 上的 debug 模块
    use std::debug;
 
    const ONE: u64 = 1;
 
    fun main(x: u64) {
        let sum = x + ONE;
        debug::print(&sum)
    }
}

脚本功能非常有限——它们不能声明友元、结构体类型或访问全局存储。其主要目的是调用模块函数。

模块

模块的语法如下:

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

其中 <address> 是有效的 named or literal address

例如:

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

module 0x42::example 这部分指定了模块 example 将被发布到 global storage中的 account address 0x42 下。

模块也可以使用 named addresses 来声明。例如:

module example_addr::example {
    struct Example has copy, drop { a: address }
 
    use std::debug;
    friend example_addr::another_example;
 
    public fun print() {
        let example = Example { a: @example_addr };
        debug::print(&example)
    }
}

由于命名地址仅在源代码层面和编译过程中存在,在字节码级别,命名地址将完全被其数值替代。

例如,如果我们有以下代码:

script {
    fun example() {
        my_addr::m::foo(@my_addr);
    }
}

并且在编译时将 my_addr 设置为 0xC0FFEE,那么在操作上它将等同于以下代码:

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

然而,在源代码层面,这两者并不等价——函数 m::foo 必须通过命名地址 my_addr 访问,而不能通过分配给该地址的数值访问。

模块名称可以以字母 azAZ 开头。在第一个字符之后,模块名称可以包含下划线 _、字母 az、字母 AZ 或数字 09

module my_module {}
module foo_bar_42 {}

通常,模块名称以小写字母开头。名为 my_module 的模块应该存储在名为 my_module.move 的源文件中。module 代码块内的所有元素可以以任意顺序出现。
本质上,模块是 typesfunctions 的集合。
use 关键字用于从其他模块导入类型。
friend 关键字用于指定受信任的模块列表。
const 关键字用于定义可在模块函数中使用的私有常量。