Skip to content
📖 Auto 编程语言(主书)本书目录

包与模块 ​

随着你的程序从单文件脚本成长为完整的应用程序,你需要一种将代码组织到多个文件和目录中的方法。你还需要一种管理依赖的方式——引入他人编写的库,并跟踪你使用的版本。

Auto 通过 automan(其包管理器和构建工具)结合模块系统提供了一套完整的项目管理方案。模块系统让你控制可见性,并将代码组织成干净、可复用的单元。

在本章中,我们将讨论:

  • 使用 automan 管理项目 —— 包管理器和构建系统
  • auto.toml —— 项目清单和依赖声明
  • 定义模块 —— mod 关键字和嵌套模块
  • 控制可见性 —— pub 关键字和默认私有
  • 组织到文件 —— 多文件项目和 use 关键字

使用 automan 管理项目 ​

automan 是 Auto 的包管理器和构建工具,等价于 Rust 的 Cargo 或 Node.js 的 npm。它负责创建项目、构建代码、运行测试和管理依赖——全部通过一个命令行工具完成。

创建新项目 ​

要创建一个新的 Auto 项目,运行 automan new:

console
$ automan new my_project
     Created binary (application) `my_project` package
$ cd my_project

这将生成一个具有以下结构的项目:

由 `automan new` 生成的新 Auto 项目

项目目录包含两个关键项:

  • auto.toml —— 项目清单文件(我们接下来详细讨论)
  • src/main.auto —— 应用程序的入口点,包含 main 函数

你可以使用 automan run 构建并运行项目,它会编译所有 .auto 文件并执行生成的二进制文件。

automan 常用命令 ​

命令描述
automan new <name>创建新项目
automan build编译项目
automan run构建并运行
automan test运行测试
automan add <dep>添加依赖

auto.toml ​

auto.toml 文件是项目清单。它位于项目根目录,描述包的元数据和依赖。它使用 TOML 格式,与 Rust 的 Cargo.toml 相同。

包元数据 ​

每个 auto.toml 以 [package] 部分开始:

toml
[package]
name = "my_project"
version = "0.1.0"

这告诉 automan 包的名称和版本。名称必须是有效的标识符——使用下划线而非连字符。

声明依赖 ​

要使用外部库,将它们添加到 [dependencies] 部分:

在 `auto.toml` 中声明依赖的项目

当你运行 automan build 时,它会读取 auto.toml,从包注册中心下载指定的依赖,并将它们一起编译。解析出的确切版本记录在 auto.lock 中,确保可重现的构建。

Auto 与 Rust 工具链对比 ​

概念AutoRust
包管理器automancargo
配置文件auto.tomlCargo.toml
锁文件auto.lockCargo.lock
编译器autocrustc
源文件.auto.rs

定义模块 ​

模块 是一个命名空间,将相关的函数、类型和常量组织在一起。在 Auto 中,你使用 mod 关键字后跟一个代码块来定义模块:

使用 `mod` 定义模块

输出:

Server started on port 8080
Connecting to localhost

mod 关键字创建一个命名空间。在 mod server { ... } 中,函数 start 被组织在 server 命名空间下。你通过点号访问它:server.start()。

模块可以嵌套。你可以在一个 mod 块内放置另一个 mod 块来创建层次结构:

auto
mod network {
    mod tcp {
        fn listen(port int) {
            print("TCP listening on port " + port)
        }
    }
}

fn main() {
    network.tcp.listen(3000)
}

这在各语言中的映射:

  • Rust 使用 mod 块配合 :: 路径分隔符。模块内的函数需要标记 pub 才能从外部访问。
  • Python 将模块展平为带前缀的函数名(server_start、client_connect)。
  • C 使用带前缀的函数名,与 Python 类似。
  • TypeScript 使用驼峰式前缀名(serverStart、clientConnect)。

控制可见性 ​

Auto 遵循 Rust 的设计哲学:所有内容_默认私有_。模块内的项只在该模块内可见,除非你用 pub 显式标记为公开。

使用 `pub` 控制可见性

输出:

public helper

pub 关键字使 helper 可以从 utils 模块外部访问。internal 函数没有 pub,所以它是私有的——只有 utils 内部的代码才能调用它。尝试从 main 调用 utils.internal() 会导致编译错误。

这是借鉴自 Rust 的刻意设计选择。默认私有意味着:

  • 你必须显式决定暴露什么。公开的 API 表面总是有意为之。
  • 内部实现细节保持隐藏。你可以重构模块的内部而不破坏使用它的代码。
  • 编译器在编译时捕获对私有项的意外访问。

可见性在各语言中的映射:

  • Rust 使用相同的 pub 关键字和相同的默认私有语义。
  • Python 没有原生的可见性控制——_ 前缀约定表示"内部"但不强制执行。转译器将调用注释掉。
  • C 使用 static 实现文件级私有函数。
  • TypeScript 没有模块级可见性;转译器添加 // private 注释并注释掉调用。

组织到文件 ​

随着项目增长,你会想将模块拆分到单独的文件中。Auto 遵循与 Rust 类似的约定:每个文件是一个模块,目录创建嵌套的模块命名空间。

项目结构 ​

一个典型的多文件 Auto 项目如下:

text
my_project/
├── auto.toml
└── src/
    ├── main.auto
    ├── utils.auto
    └── network/
        ├── mod.auto
        ├── server.auto
        └── client.auto

每个 .auto 文件成为一个模块。目录 network/ 成为 network 模块命名空间,其中 mod.auto 是其入口点。

use 关键字 ​

use 关键字将模块引入作用域,使你可以直接引用其中的项。这类似于 Rust 的 use 或 Python 的 import:

使用 `use` 导入的多文件项目

输出:

public helper
Server started on port 8080

use utils 将 utils 模块引入作用域。use network.server 将 network 目录中的 server 子模块引入作用域。导入后,你可以直接调用 utils.helper() 和 server.start()。

注意两种 use 形式的区别:

  • use utils —— 导入模块作为命名空间。你仍然通过它访问项:utils.helper()。
  • use network.server —— 导入特定的子模块。你可以直接调用其函数:server.start()。

use 在各语言中的映射:

  • Rust 为基于文件的模块生成 mod 声明,使用 :: 表示路径。
  • Python 生成 from ... import ... 语句。
  • C 内联函数定义并添加注释标明来源。
  • TypeScript 内联函数并添加注释标明来源模块。

文件命名约定 ​

Auto 遵循以下文件到模块的映射约定:

文件模块路径
src/main.auto(二进制入口点)
src/utils.autoutils
src/network/mod.autonetwork(目录模块)
src/network/server.autonetwork::server
src/network/client.autonetwork::client

每个目录必须有一个 mod.auto 文件作为模块入口点。该文件可以重新导出子模块或直接定义项。

总结 ​

Auto 的包和模块系统提供了在任何规模下组织代码的工具:

概念AutoRust
包管理器automancargo
项目清单auto.tomlCargo.toml
锁文件auto.lockCargo.lock
定义模块mod name { }mod name { }
设为公开pub fnpub fn
默认可见性私有私有
导入模块use namemod name; / use name::item;
源文件.auto.rs
目录模块mod.automod.rs

关键设计原则:

  1. 默认私有:你必须用 pub 显式选择将项公开。这使你的 API 表面是有意且可控的。

  2. 显式导入:use 关键字使文件间的依赖一目了然。你总能看到函数来自哪里。

  3. 约定优于配置:文件到模块的映射遵循可预测的规则。src/utils.auto 成为 utils 模块。src/network/server.auto 成为 network::server。

  4. 可重现构建:auto.lock 锁定确切的依赖版本,使构建在不同机器上具有确定性。

在下一章中,我们将探讨 Auto 如何处理集合——你将在组织好的模块中每天使用的数据结构。

基于 MIT 许可发布。