使用 Rust 的单一代码库:代码组织实践
\n\n在开发大型 Rust 项目时,迟早会遇到一个问题:如何组织代码,使其保持可维护、可复用且易于扩展?一种流行的方法是单一代码库。在本文中,我们将探讨在 Rust 上下文中什么是单一代码库,如何使用 Cargo Workspaces 进行配置,以及哪些实用技巧有助于避免代码库混乱。
本文对刚开始处理大型项目的新手,以及寻求高效代码组织方法的有经验开发者都会有所帮助。
\n\n什么是单一代码库,为什么在 Rust 中需要它?
\n\n单一代码库 (monorepo) 是一种方法,其中整个项目(或多个相关项目)的代码存储在一个仓库中。这与多仓库方法不同,后者中每个服务或库都存在于独立的 Git 仓库中。
\n\n为什么 Rust 开发者经常选择单一代码库?
\n- \n
- 统一的依赖版本。 您可以避免不同 crate 需要同一库的不同版本时产生的冲突。 \n
- 简化的重构。 在一个 crate 中更改 API 会立即在所有依赖的 crate 中可见——Rust 编译器会指出所有需要修改的地方。 \n
- 联合编译。 Cargo 可以优化构建过程,重用已编译的工件。 \n
- 统一的变更历史。 您无需在不同仓库之间同步提交。 \n
在 Rust 中组织单一代码库的主要工具是 Cargo Workspaces。让我们看看如何在实际中使用它。
\n\n配置 Cargo Workspaces:分步示例
\n\n假设我们正在创建一个由三部分组成的应用程序:
\n- \n
- 库
core_lib— 通用逻辑; \n - 库
utils— 工具函数; \n - 可执行文件
app— 主二进制文件。 \n
让我们创建单一代码库的结构:
\n\nmy_monorepo/\n├── Cargo.toml # 根 workspace 清单\n├── core_lib/\n│ ├── Cargo.toml\n│ └── src/\n│ └── lib.rs\n├── utils/\n│ ├── Cargo.toml\n│ └── src/\n│ └── lib.rs\n└── app/\n ├── Cargo.toml\n └── src/\n └── main.rs\n\n\n步骤 1. 根 Cargo.toml
[workspace]\nmembers = [\n "core_lib",\n "utils",\n "app",\n]\n\n\n现在所有三个 crate 都是同一个 workspace 的一部分。Cargo 会将它们作为一个整体进行管理。
\n\n步骤 2. 内部依赖
\n在 app/Cargo.toml 文件中,指定它依赖于我们的库:
[package]\nname = "app"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\ncore_lib = { path = "../core_lib" }\nutils = { path = "../utils" }\n\n\n步骤 3. 编写代码
\ncore_lib/src/lib.rs 中的代码示例:
pub fn greet(name: &str) -> String {\n format!("Hello, {}!", name)\n}\n\n\n在 app/src/main.rs 中使用此函数:
use core_lib::greet;\n\nfn main() {\n println!("{}", greet("Rust Developer"));\n}\n\n\n步骤 4. 构建和运行
\ncargo build、cargo test 和 cargo run 命令适用于整个 workspace。您也可以运行特定的 crate:
cargo run -p app\ncargo test -p core_lib\n\n\n这是基本配置。现在让我们转向更高级的实践。
\n\n高级组织:模块、测试和版本控制
\n\n当 crate 数量增多时,保持纪律很重要。以下是一些经过验证的