Rust - 模块
Rust - 模块、包和工作区
Section titled “Rust - 模块、包和工作区”随着项目规模的增长,代码组织变得至关重要。Rust 提供了一个强大的系统,基于包(crates)、模块(modules)和工作区(workspaces)。
| 术语 | 描述 |
|---|---|
| 包(Crate) | Rust 中最小的编译单元。包可以是二进制包(一个带有 main 函数的可执行程序)或库包(可重用代码的集合)。 |
| 包(Package) | 零个或多个包的捆绑,提供一组功能。包包含一个 Cargo.toml 文件,描述如何构建这些包。一个包最多可以包含一个库包,但可以包含许多二进制包。 |
| 模块(Module) | 一种将包内的代码组织成逻辑单元并控制项目可见性(公共/私有)的方式。 |
| 工作区(Workspace) | 一组共享公共 Cargo.lock 文件和输出目录的包。非常适合管理具有多个相互连接组件的大型项目。 |
定义和使用模块
Section titled “定义和使用模块”模块使用 mod 关键字声明。默认情况下,模块内的所有内容都是私有的。使用 pub 关键字可以使项(模块、函数、结构体等)变为公共的,并可从模块外部访问。
mod network { // 此函数对 `network` 模块私有。 fn connect() { println!("Private connect function called"); }
// 此模块是公共的。 pub mod server { // 此函数是公共的,因此可以从外部调用。 pub fn listen() { println!("Listening on server..."); // 我们可以从同一个父模块调用私有函数。 super::connect(); } }}
fn main() { // 这之所以有效,是因为 `server` 和 `listen` 都是公共的。 network::server::listen();
// 这将导致编译失败,因为 `connect` 是私有的: // network::connect();}使用 use 将路径引入作用域
Section titled “使用 use 将路径引入作用域”输入完整的路径(如 network::server::listen)可能会很繁琐。use 关键字可以为路径创建快捷方式,使代码更简洁。
// ... (上面定义的 network 模块)
// 将 `listen` 函数引入当前作用域use network::server::listen;
fn main() { // 现在我们可以直接调用它 listen();}习惯上使用 use 将结构体、枚举和其他项完全引入作用域。对于函数,通常更清晰的做法是引入父模块并使用其模块前缀调用函数(例如 server::listen()),以明确函数来源。
项目:在工作区中创建和使用库包
Section titled “项目:在工作区中创建和使用库包”让我们创建一个更真实的工程结构:一个包含应用程序逻辑库和一个使用该库的二进制的工作区。
步骤 1:创建工作区
Section titled “步骤 1:创建工作区”mkdir media_appcd media_apptouch Cargo.toml编辑 media_app/ 根目录下的新 Cargo.toml 文件,将其定义为工作区:
[workspace]
members = [ "media_lib", "media_cli",]步骤 2:创建库包
Section titled “步骤 2:创建库包”在 media_app 目录内部,使用 Cargo 创建库包:
cargo new media_lib --lib编辑 media_app/media_lib/src/lib.rs 以包含我们的公共 API:
/// 一个用于播放媒体的公共函数。pub fn play(name: &str) { println!("Playing media: {}", name);}
/// 一个表示音频轨道的公共结构体。pub struct Audio { pub title: String, pub artist: String,}步骤 3:创建二进制包
Section titled “步骤 3:创建二进制包”现在,创建将使用我们库的命令行应用程序:
cargo new media_cli步骤 4:添加库作为依赖项
Section titled “步骤 4:添加库作为依赖项”编辑 media_app/media_cli/Cargo.toml 来告知它关于 media_lib:
[package]name = "media_cli"version = "0.1.0"edition = "2021"
[dependencies]media_lib = { path = "../media_lib" }步骤 5:在二进制中(使用)库
Section titled “步骤 5:在二进制中(使用)库”最后,编辑 media_app/media_cli/src/main.rs 以调用我们库的代码:
// 使用我们本地库包中的项use media_lib::{play, Audio};
fn main() { println!("--- Media CLI Application ---");
// 调用库函数 play("Interstellar Soundtrack.mp4");
// 使用库结构体 let track = Audio { title: "Time".to_string(), artist: "Hans Zimmer".to_string(), };
println!("Now loading audio: '{}' by {}", track.title, track.artist);}步骤 6:运行应用程序
Section titled “步骤 6:运行应用程序”从工作区根目录(media_app/)中,你可以专门运行二进制包:
cargo run -p media_cli Compiling media_lib v0.1.0 (...) Compiling media_cli v0.1.0 (...) Finished dev [unoptimized + debuginfo] target(s) in ... Running `target/debug/media_cli`--- Media CLI Application ---Playing media: Interstellar Soundtrack.mp4Now loading audio: 'Time' by Hans Zimmer