[自用]Rust速通day5:包、crate和use

模块

包和Crate

首先介绍crate,由于Rust官方文档讲述过于晦涩,我只讲述自己的理解:

crate本身是一个抽象的概念,可以理解成是实现特定功能的集合,有多个.rs文件组成。

crate分为两种:二进制crate和库crate,

二进制crate中必须包含一个main函数来定义程序被执行的时候需要做的事,可以被编译成可执行程序,一个包内有可以有多个二进制crate。

而库crate则是实现功能并提供api接口,提供了能给多个项目复用的功能,一个包内只能有一个。

一个包内至少包含一个crate(不管是库还是二进制)。

是crate构建的入口,在运行指令cargo build之后,会从根开始构建起整个模块树

接下来会用一个例子来详细说明:

我现在需要构造一个智能家具系统,文件结构如下:

复制代码
smart_home/                      # 包根目录
├── Cargo.toml                   # 包配置文件
└── src/                         # 源代码目录
    ├── lib.rs                    # 库 crate 的根
    ├── device.rs                 # 库 crate:设备通用接口
    ├── temperature.rs            # 库 crate:温度传感器相关功能
    ├── logger.rs                 # 库 crate:日志功能
    ├── main.rs                   # 二进制 crate "smart_home" 的根
    ├── ac_control.rs             # 二进制 crate "smart_home" 的私有模块:空调控制
    ├── fridge_control.rs         # 二进制 crate "smart_home" 的私有模块:冰箱控制
    └── bin/                      # 存放其他二进制 crate 的根文件
        ├── mobile_app.rs          # 二进制 crate "mobile_app" 的根
        ├── mobile_app/            # mobile_app 的私有模块目录
        │   ├── ui.rs              # mobile_app 的私有模块:界面
        │   └── notify.rs          # mobile_app 的私有模块:通知
        ├── web_dashboard.rs       # 二进制 crate "web_dashboard" 的根
        └── web_dashboard/         # web_dashboard 的私有模块目录
            ├── charts.rs          # web_dashboard 的私有模块:图表
            └── auth.rs            # web_dashboard 的私有模块:认证

里面有三个二进制crate:smart_homemobile_appweb_dashboard,分别负责智能家居的总调控,手机app功能实现,网页功能实现,并且构建了库crate,包含多个模块文件。每个crate都有自己的根。(通常main.rs是主程序的根,lib.rs是库crate的根,其他二进制crate的根统一储存在文件夹src/bin/内,并且每一个src/bin下的文件都会被编译成一个独立的二进制crate)

smart_home以根main.rs开始,再通过文件内的mod声明查找对应的文件并纳入模块树中,类似于:

rust 复制代码
// src/main.rs

mod ac_control  // 告诉编译器存在一个 ac_control 模块,它将在 ac_control.rs 或 ac_control/mod.rs 中定义
mod fridge_control
mod device //引入 库crate 的 device 模块

这些模块共同构成了一个实现家具控制的功能集合,也就是二进制crate。

在实际的实现过程中,如果一个模块(比如目录中的device文件)同时被另一个二进制 crate 通过 mod 引入,那么它们会在那个二进制 crate 中被再次编译,形成两份独立的代码副本。这可不是我们想要看到的。

因此我们在二进制crate之外还有库crate,能让我们把共享代码放在库crate中,然后让二进制 crate 通过依赖来使用,而不是直接复制模块文件,从而实现功能的复用

use将路径引入作用域

use的作用可以理解为是快捷方式,通过创建一个快捷方式把特定的模块导入到"桌面",也就是作用域中。这样我们就不用写繁琐的前缀了,可以直接使用。例如以下代码:

rust 复制代码
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

如果没有use的话,我们就需要写crate::front_of_house::hosting::add_to_waitlist()

你可以理解成他其实是在crate的作用域中创建了一个虚拟的mod hosting

但是注意use只能创建use所在的特定作用域的捷径,也就是说,如果把eat_at_restaurant()移动到子模块customer中,就到了另一个作用域,因此无法访问hosting::add_to_waitlist()

解决方法是在子模块中重新使用use构造捷径。就像这样:

rust 复制代码
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}
use crate::front_of_house::hosting;
mod customer {
    pub fn eat_at_restaurant() {
        use crate::front_of_house::hosting;
        hosting::add_to_waitlist();
    }
}

另一个解决方法是使用pub use重新导出,这样子导出的模块会暴露在所有作用域下:

rust 复制代码
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}
pub use crate::front_of_house::hosting;
mod customer {
    pub fn eat_at_restaurant() {
        hosting::add_to_waitlist();
    }
}

当你代码的内部结构与调用你代码的程序员所想象的结构不同时,重导出会很有用。例如,在这个餐馆的比喻中,经营餐馆的人会想到"前台"和"后台"。但顾客在光顾一家餐馆时,可能不会以这些术语来考虑餐馆的各个部分。使用 pub use,我们可以使用一种结构编写代码,却将 不同的结构形式暴露出来。这样做使我们的库井井有条,也使开发这个库的程序员和调用这个库的程序员都更加方便。

你可能会有这样的疑惑:如果我要用函数add_to_waitlist()的话,为什么我不用use crate::front_of_house::hosting::add_to_waitlist()直达,然后直接使用函数呢?

原因是因为这不符合习惯,上面展示的写法可以清晰地区分函数是不是在本地定义的 ,同时也可以让路径的重复度减小。另一方面,使用use引入结构体、枚举以及其他项的时候,习惯是指定他们的完整路径,比如以下把HashMap结构体引入二进制crate作用域的做法:

rust 复制代码
use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert(1, 2);
}
相关推荐
Ivanqhz4 小时前
活跃范围重写(Live Range Rewriting)
开发语言·c++·后端·算法·rust
Roc.Chang9 小时前
Rust 入门 - RustRover 新建项目时四种项目模板对比
开发语言·后端·rust
勇敢牛牛_1 天前
【conreg-client】在Rust中使用向Feign一样的远程调用
网络·rust·feign
小杍随笔1 天前
【Rust模块化进阶:深入解析mod.rs的用法与现代实践(1.94版本)】
开发语言·后端·rust
@atweiwei1 天前
Tokio 深度解析:Rust 异步运行时与 Go 协程对比指南
服务器·网络·后端·golang·rust·内存·所有权
福大大架构师每日一题1 天前
2026年3月TIOBE编程语言排行榜,Go语言排名第16,Rust语言排名14。为什么 TIOBE 指数仍然依赖搜索引擎?
开发语言·搜索引擎·rust·tiobe
小杍随笔1 天前
【Rust可见性控制:pub、pub(crate)、pub(super)实战】
开发语言·后端·rust
Source.Liu1 天前
【Iced】core库下angle.rs文件分析
rust·iced
Source.Liu1 天前
【A11】a11lib 库作为外部库接口层的设计理念
rust·iced