Rust 学习笔记:Cargo 工作区

article/2025/6/7 14:55:30

Rust 学习笔记:Cargo 工作区

  • Rust 学习笔记:Cargo 工作区
    • 创建工作区
    • 在工作区中创建第二个包
    • 依赖于工作区中的外部包
    • 向工作区添加测试
    • 将工作区中的 crate 发布到 crates.io
    • 添加 add_two crate 到工作区
    • 总结

Rust 学习笔记:Cargo 工作区

随着项目的发展,库 crate 可能会越来越大,你可能希望将包(package)进一步拆分为多个库 crate。Cargo 提供了一个称为工作区(Workspaces)的特性,它可以帮助管理串联开发的多个相关包。

创建工作区

工作区是一组共享相同 Cargo.lock 和输出目录的包。

构建工作区有多种方法,我们只展示一种常见的方法。我们将有一个包含二进制文件和两个库的工作区。提供主要功能的二进制文件将依赖于这两个库。一个库提供一个 add_one 函数,另一个库提供一个 add_two 函数。这三个 crate 将是同一个工作区的一部分。

我们首先为工作区创建一个新目录:

$ mkdir add
$ cd add

接下来,在 add 目录中,我们创建 Cargo.toml 文件,它将配置整个工作区。这个文件没有 [package] 部分。相反,它将以一个 [workspace] 部分开始,该部分将允许我们向工作区添加成员。通过将解析器设置为 3,我们还强调在工作区中使用 Cargo 解析器算法的最新和最好版本。

[workspace]
resolver = "3"

接下来,我们将通过在 add 目录中运行 cargo new 来创建加法器二进制 crate:

在这里插入图片描述

在工作区内运行 cargo new 还会自动将新创建的包添加到工作区内 Cargo.toml 的 [workspace] 定义中的 members 键中,如下所示:

在这里插入图片描述

此时,我们可以通过运行 cargo build 来构建工作区。add 目录下的文件应该是这样的:

├── Cargo.lock
├── Cargo.toml
├── adder
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target

工作区在顶层有一个目标目录,编译后的工件将被放置到该目录中。adder 包没有自己的目标目录。即使我们要从 adder 目录中运行 cargo build,编译后的工件仍然会在 add/target 而不是 add/adder/target 中结束。Cargo 在工作区的目标目录中采用这样的结构,因为工作区的 crate 是相互依赖的。如果每个 crate 都有自己的目标目录,那么每个 crate 都必须重新编译工作区中的其他 crate,以便将工件放置在自己的目标目录中。通过共享一个目标目录,crate 可以避免不必要的重新构建。

在工作区中创建第二个包

接下来,让我们在工作区中创建另一个成员包,并将其命名为 add_one。

生成一个名为 add_one 的库 crate:

在这里插入图片描述

顶层的 Cargo.toml 文件现在将在 members 列表中包含 add_one 路径:

在这里插入图片描述

add 目录下的文件树为:

├── Cargo.lock
├── Cargo.toml
├── add_one
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── adder
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target

在 add_one/src/lib.rs 中添加一个 add_one 函数:

pub fn add_one(x: i32) -> i32 {x + 1
}

现在,我们让 adder 包依赖 add_one 库。首先,我们需要在 adder/Cargo.toml 上添加一个对 add_one 的路径依赖。

[dependencies]
add_one = { path = "../add_one" }

Cargo 并不假设工作区中的 crate 将相互依赖,因此我们需要明确依赖关系。

接下来,让我们在 adder crate 中使用 add_one 函数,修改 adder/src/main.rs:

fn main() {let num = 10;println!("Hello, world! {num} plus one is {}!", add_one::add_one(num));
}

在顶级的 add 目录中运行 cargo build 来构建工作区。

要从 add 目录运行二进制 crate,我们可以使用 cargo run 加上 -p 参数后接包名来指定我们想要运行的工作区中的哪个包。

在这里插入图片描述

运行了 adder/src/main.rs 中的代码,代码依赖于 add_one crate。

依赖于工作区中的外部包

注意,工作区在顶层只有一个 Cargo.lock 文件,而不是在每个 crate 的目录中都有一个 Cargo.lock。这确保了所有的 crate 都使用相同版本的所有依赖项。

如果我们将 rand 包添加到 adder/Cargo.toml 和 add_one/Cargo.toml 文件中,Cargo 将把这两个包解析为一个 rand 版本,并将其记录在一个 Cargo.lock 中。

让工作区中的所有 crate 使用相同的依赖关系意味着这些 crate 将始终相互兼容。让我们将 rand crate 添加到 add_one/Cargo.toml 文件的 [dependencies] 部分,这样我们就可以在 add_one crate 中使用 rand crate 了:

[dependencies]
rand = "0.8.5"

我们现在可以在 add_one/src/lib.rs 中添加 use rand;。通过在 add 目录中运行 cargo build 来构建整个工作区,将引入并编译 rand crate。我们将得到一个警告,因为我们没有引用我们带入范围的 rand:

在这里插入图片描述

即使在工作区的某个地方使用了 rand,我们也不能在工作区的其他 crate 中使用它,除非我们也将 rand 添加到它们的 Cargo.toml 文件中。

例如,如果我们将 use rand; 添加到 adder/src/main.rs 文件中,我们将得到一个错误:

在这里插入图片描述

要解决这个问题,需要编辑 adder/Cargo.toml 文件,并指出 rand 也是它的依赖项。

[dependencies]
add_one = { path = "../add_one"}
rand = "0.8.5"

构建 adder 包会将 rand 添加到 Cargo.lock 中 adder 的依赖列表中,但不会下载 rand 的其他副本。Cargo 的语义版本规则将确保工作区中使用 rand 包的每个包中的每个 crate 使用相同的版本,只要它们指定 rand 的兼容版本,就可以节省空间,并确保工作区中的 crate 彼此兼容。

假设同一工作区中有一个 crate 依赖 rand 0.8.0,另一个 crate 依赖 rand 0.8.1。根据语义版本规则,这两个语义版本是兼容的,所以这两个 crate 都使用 rand 0.8.1,或者使用更新的补丁版本,比如 0.8.2。

如果工作区中的 crate 指定了相同依赖项的不兼容版本,Cargo 将解析每个版本,但仍将尝试解析尽可能少的版本。

假设同一工作区中有一个 crate 依赖 rand 0.8.0,另一个 crate 依赖 rand 0.7.0。因为语义版本不兼容,Cargo 为每个 crate 使用不同版本的 rand。

向工作区添加测试

在 add_one crate 中添加一个对 add_one 函数的测试:

pub fn add_one(x: i32) -> i32 {x + 1
}#[cfg(test)]
mod tests {use super::*;#[test]fn it_works() {assert_eq!(3, add_one(2));}
}

现在在顶级 add 目录中运行 cargo test。在这样的工作区中运行 cargo test 将为工区中的所有 crate 运行测试:

在这里插入图片描述

输出的第一部分显示通过了 add_one crate 中的 it_works 测试。下一节显示在 adder crate 中没有找到任何测试,最后一节显示在 add_one crate 中没有找到任何文档测试。

我们还可以通过使用 -p 标志并指定我们想要测试的 crate 的名称,在顶层目录下对工作区中的特定 crate 运行测试:

在这里插入图片描述

该输出显示 cargo test 只运行了add_one crate 的测试,而没有运行 adder crate 的测试。

将工作区中的 crate 发布到 crates.io

如果将工作区中的 crate 发布到 crates.io,那么工作区中的每个 crate 都需要单独发布。与 cargo test 类似,我们可以通过使用 -p 标志并指定我们想要发布的 crate 的名称,在工作区中发布特定的 crate。

添加 add_two crate 到工作区

以与 add_one crate 类似的方式将 add_two crate 添加到该工作区。

在这里插入图片描述

adder/Cargo.toml:

[dependencies]
add_one = { path = "../add_one"}
add_two = { path = "../add_two"}
rand = "0.8.5"

在 add_two/src/lib.rs 中添加以下代码:

pub fn add_two(x: i32) -> i32 {x + 2
}#[cfg(test)]
mod tests {use super::*;#[test]fn it_works() {assert_eq!(4, add_two(2));}
}

修改 adder/src/main.rs:

fn main() {let num = 10;println!("Hello, world! {num} plus one is {}!", add_one::add_one(num));println!("Hello, world! {num} plus two is {}!", add_two::add_two(num));
}

运行 cargo run:

在这里插入图片描述

运行 cargo test:

PS C:\Users\81228\Documents\Program\Rust Project\add> cargo testCompiling add_two v0.1.0 (C:\Users\81228\Documents\Program\Rust Project\add\add_two)Compiling adder v0.1.0 (C:\Users\81228\Documents\Program\Rust Project\add\adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.43s                                                                                                           Running unittests src\lib.rs (target\debug\deps\add_one-a59b5500767c3a29.exe)running 1 test
test tests::it_works ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sRunning unittests src\lib.rs (target\debug\deps\add_two-927f837920a25f8c.exe)running 1 test
test tests::it_works ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sRunning unittests src\main.rs (target\debug\deps\adder-30ef0042878a10a4.exe)running 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests add_onerunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests add_tworunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

运行 cargo test -p add_two:

在这里插入图片描述

总结

随着项目的增长,请考虑使用工作区:它使得开发者能够使用更小、更容易理解的组件,而不是使用一大块代码。此外,如果经常同时更改,则将 crate 保存在工作区中可以使它们之间的协调更容易。


http://www.hkcw.cn/article/HjWRbdYFjC.shtml

相关文章

操作系统 第 39 章 插叙:文件和目录

两项关键操作系统技术的发展:进程,虚拟化的 CPU;地址空间,虚拟化的内存。 这一部分加上虚拟化拼图中最关键的一块:持久存储。永久存储设备永久地(或至少长时间地)存储信息,如传统硬盘…

楼宇自控系统联动暖通空调:解密建筑环境舒适度提升路径

走进现代建筑,无论是办公场所、商业中心,还是医院、酒店,人们对环境舒适度的要求越来越高。暖通空调作为调节建筑室内环境的关键设备,其运行效果直接影响着人们的体验。然而,传统暖通空调独立运行、调控不灵活等问题&a…

Freemarker快速入门

Freemarker概述 FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库&#xff0c…

黑盒(功能)测试基本方法

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、黑盒测试的概念 1、什么是黑盒测试 (1)黑盒测试又称功能测试、数据驱动测试或基于规格说明书的测试,是一种从用户观点出…

[java八股文][JavaSpring面试篇]SpringCloud

了解SpringCloud吗,说一下他和SpringBoot的区别 Spring Boot是用于构建单个Spring应用的框架,而Spring Cloud则是用于构建分布式系统中的微服务架构的工具,Spring Cloud提供了服务注册与发现、负载均衡、断路器、网关等功能。 两者可以结合…

chromedriver 下载失败

问题描述 chromedriver 2.46.0 下载失败 淘宝https://registry.npmmirror.com/chromedriver/2.46/chromedriver_win32.zip无法下载 解决方法 找到可下载源 https://cdn.npmmirror.com/binaries/chromedriver/2.46/chromedriver_win32.zip ,先将其下载到本地目录(D…

74. 搜索二维矩阵 (力扣)

给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。…

CppCon 2014 学习:Rolling Your Own Circuit Simulator

这段话讲述了一个背景和动机,目的是阐明为什么开源C库变得越来越复杂且在科学和工程领域有很大的应用潜力。 关键点: 开源库的成熟: 近年来,开源C库在许多科学和工程领域变得越来越成熟和强大。这些库不再仅仅是简单的工具&…

无人机自主降落论文解析

Dynamic Landing of an Autonomous Quadrotor on a Moving Platform in Turbulent Wind Conditions 滑膜控制器 这一部分详细介绍了边界层滑模控制器(Boundary Layer Sliding Controller,BLSC)的设计和实现,特别是如何将其应用于…

.NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想

在当今数据驱动的时代,向量数据库(Vector Database)作为一种新兴的数据库技术,正逐渐成为软件开发领域的重要组成部分。特别是在 .NET 生态系统中,向量数据库的应用为开发者提供了构建智能、高效应用程序的新途径。 一…

html基础01:前端基础知识学习

html基础01&#xff1a;前端基础知识学习 1.个人建立打造 -- 之前知识的小总结1.1个人简历展示1.2简历信息填写页面 1.个人建立打造 – 之前知识的小总结 1.1个人简历展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8&qu…

CentOS Stream 8 Unit network.service not found

一、问题现象 在 CentOS Stream 8 操作系统中&#xff0c;配置完静态IP 信息&#xff0c;想重启网络服务。 执行如下命令&#xff1a; systemctl restart network 提示信息如下&#xff1a; Failed to restart network.service: Unit network.service not found. 二、问题…

【Axure高保真原型】交通事故大屏可视化分析案例

今天和大家分享交通事故大屏可视化分析案例的原型模板&#xff0c;包括饼图分类分析、动态显示发生数、柱状图趋势分析、中部地图展示最新事故发现地点和其他信息、右侧列表记录发生事故的信息…… 通过多种可视化图表展示分析结果&#xff0c;具体效果可以点击下方视频观看或…

网络安全-等级保护(等保) 3-3-1 GB/T 36627-2018 附录A (资料性附录) 测评后活动、附 录 B (资料性附录)渗透测试的有关概念说明

################################################################################ GB/T 36627-2018 《信息安全技术 网络安全等级保护测试评估技术指南》对网络安全等级保护测评中的相关测评技术进行明确的分类和定义,系统地归纳并阐述测评的技术方法,概述技术性安全测试和…

wsl===windows下安装Linux系统

新近版本的windows都支持了Linux&#xff0c;操作如下&#xff1a; 控制面板中启用对应的功能 2. 打开powershell&#xff0c;以安装Ubuntu为例&#xff0c;然后执行 PS C:\Users\steven.wang> wsl.exe --update 正在安装: 适用于 Linux 的 Windows 子系统 已安装 适用于 …

云上展厅颠覆传统展览

云上展厅&#xff1a;重塑展览行业的新篇章 随着数字化技术的迅猛发展&#xff0c;传统展览模式正经历一场深刻的变革。云上展厅&#xff0c;新兴的展览形式&#xff0c;正逐步颠覆传统的实体展览模式&#xff0c;凭借其跨越时空限制、多样化展示方式、丰富互动体验及高效商业…

谷歌地图苹果版v6.138.2 - 前端工具导航

谷歌地图(Google maps)苹果版是是由谷歌官方推出的一款手机地图应用。软件功能强大&#xff0c;支持本地搜索查找世界各地的地址、地点和商家&#xff1b;支持在街景视图中查看世界各地的360度全景图&#xff1b;支持查找乘坐火车、公交车和地铁的路线&#xff0c;或者查找步行…

Microsoft前后端不分离编程新风向:cshtml

文章目录 什么是CSHTML&#xff1f;基础语法内联表达式代码块控制结构 布局页面_ViewStart.cshtml_Layout.cshtml使用布局 模型绑定强类型视图模型集合 HTML辅助方法基本表单验证 局部视图创建局部视图使用局部视图 高级特性视图组件依赖注入Tag Helpers 性能优化缓存捆绑和压缩…

事件对象以及常见属性

1.1获取事件对象 1.2语法 1.3事件对象属性

ssh登录wsl2

1. ssh服务重新安装 Ubuntu20.04子系统自带的ssh服务无法连接&#xff0c;需卸载后重新安装。 sudo apt-get remove openssh-server sudo apt-get install openssh-server2. 修改配置信息 sudo vim /etc/ssh/sshd_config修改内容&#xff1a; # 最好一模一样 Port 33 # 这…