rust package crates modules的使用

最后发布时间:2026-02-13 15:09:03 浏览量:

在 Rust 中,Package(包)Crate(单元)Module(模块) 是组织代码的三个核心概念。理解它们的关系对编写清晰、可维护的 Rust 项目至关重要。


🧩 一、基本定义与关系

概念定义说明
Crate编译的基本单元一个 crate 可以是一个 库(lib)可执行程序(bin)。编译器每次只编译一个 crate。
Package一个或多个 crate 的集合 + Cargo.toml一个 package 必须包含 1 个 Cargo.toml最多包含 1 个 lib crate可包含多个 bin crate
Modulecrate 内部的命名空间和作用域用于组织代码、控制可见性(pub),可嵌套。

一句话总结
一个 Package 包含一个或多个 Crates;一个 Crate 由 Modules 组成。


📦 二、Package 详解

✅ 创建一个 package

cargo new my-project        # 默认创建 bin package
cargo new --lib my-lib      # 创建 lib package

Cargo.toml 决定 package 类型

  • Bin package(可执行)

    [package]
    name = "my-app"
    version = "0.1.0"
    
    [[bin]]
    name = "my-app"  # 对应 src/main.rs
    
  • Lib package(库)

    [package]
    name = "my-lib"
    version = "0.1.0"
    
    [lib]
    name = "my_lib"  # 对应 src/lib.rs
    
  • 同时包含 lib 和 bin(常见于 CLI 工具库):

    my-package/
    ├── Cargo.toml
    ├── src/
    │   ├── lib.rs    ← lib crate
    │   └── main.rs   ← bin crate (name = package name)
    └── src/bin/      ← 额外的可执行文件
          └── tool2.rs
    

🔸 一个 package 只能有一个 lib crate,但可以有多个 bin crate。


🧱 三、Crate 详解

  • 每个 crate 有独立的根(root)

    • lib crate 的根是 src/lib.rs
    • bin crate 的根是 src/main.rssrc/bin/*.rs
  • crate 是编译和链接的最小单位
    当你 cargo build,Rust 会为每个 crate 生成一个 .rlib 或可执行文件。

  • 外部依赖也是 crate
    例如 serdetokio 都是独立的 crates,通过 Cargo.toml 引入。


🗂️ 四、Module 详解

Module 用于 组织代码结构控制访问权限

1. 声明模块

// src/lib.rs 或 main.rs
mod network {
    pub fn connect() {
        println!("Connecting...");
    }

    fn private_helper() {} // 默认私有
}

2. 使用模块(路径)

fn main() {
    network::connect(); // ✅ 可访问 pub 函数
    // network::private_helper(); // ❌ 编译错误
}

3. 模块拆分为文件(推荐)

方式 A:单个文件

// src/network.rs
pub fn connect() { ... }

lib.rsmain.rs 中声明:

mod network; // 自动加载 src/network.rs

方式 B:模块目录(子模块)

src/
├── lib.rs
└── network/
    ├── mod.rs      ← 模块根
    ├── tcp.rs
    └── udp.rs

src/lib.rs:

mod network;

src/network/mod.rs:

pub mod tcp;
pub mod udp;

💡 从 Rust 2018 起,也可以不用 mod.rs,直接用 network.rs + network/tcp.rs,但传统方式更清晰。


🔑 五、可见性控制(pub

语法含义
fn foo()私有(仅当前模块及子模块可访问)
pub fn foo()公开(任何地方可访问)
pub(crate) fn foo()在当前 crate 内公开
pub(super) fn foo()对父模块公开
pub(in path) fn foo()在指定路径内公开

示例:

mod outer {
    pub mod inner {
        pub(super) fn visible_to_outer() {}
        pub fn visible_everywhere() {}
    }
}

// outer::inner::visible_everywhere()  ✅
// outer::inner::visible_to_outer()   ✅(因为 outer 是 super)
// inner::visible_to_outer()          ❌(不在 outer 内)

🌐 六、使用外部 crate(依赖)

  1. Cargo.toml 添加依赖:

    [dependencies]
    serde = "1.0"
    rand = "0.8"
    
  2. 在代码中引入:

    use serde::{Serialize, Deserialize};
    use rand::Rng;
    
    #[derive(Serialize)]
    struct Point { x: i32, y: i32 }
    

外部 crate 默认以 crate 名作为根模块名(如 serderand)。


🧪 七、实战示例:完整项目结构

my-cli/
├── Cargo.toml
├── src/
│   ├── main.rs          // bin crate root
│   ├── lib.rs           // lib crate root
│   └── commands/
│       ├── mod.rs
│       ├── start.rs
│       └── stop.rs

Cargo.toml:

[package]
name = "my-cli"
version = "0.1.0"

[[bin]]
name = "my-cli"
path = "src/main.rs"

[lib]
name = "my_cli"
path = "src/lib.rs"

src/lib.rs:

pub mod commands;

src/commands/mod.rs:

pub mod start;
pub mod stop;

src/main.rs:

use my_cli::commands;

fn main() {
    commands::start::run();
}

✅ 总结:关键点速记

概念关键点
PackageCargo.toml 定义,包含 0 或 1 个 lib crate + 任意数量 bin crate
Crate编译单元,lib 或 bin,是外部依赖的基本单位
Modulecrate 内部的代码组织单元,控制作用域和可见性
文件映射mod foo;foo.rsfoo/mod.rs
可见性默认私有,用 pub 控制公开范围

如果你正在设计一个库或 CLI 工具,建议:

  • 库代码放在 src/lib.rs 及其子模块
  • CLI 入口放在 src/main.rs,调用 lib 中的逻辑
  • 使用 pub use 重导出简化 API

需要我帮你设计具体项目的模块结构吗?