使用pub use导出方便使用的公共API
问题:crate的程序结构在开发时对于开发者很合理,但是对它的使用者不够方便。例如:开发者会把程序结构分为很多层,使用者想找到这种深层结构中的某个类型费时费力。例: 有这么一个类型,开发者这样定义my_crate::some_module::another_module::UsefulType,用户用的时候希望是my_crate::UsefulType 解决方法:
- 不需要重新组织内部代码的结构
- 使用pub use可以重新导出,创建一个与内部私有结构不同的对外公共结构
例:
// src/lib.rs
//! # Art
//!
//! A library for modeling artistic concepts.
pub mod kinds {
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
SecondaryColor::Green
}
}
// src/main.rs
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
可以看到,PrimaryColor和mix分别在不同的模块里。使用起来不是很友好。使用cargo doc --open生成并查看文档:

文档看起来也比较麻烦,需要点kinds和utils才能查看里的内容。
下面利用pub use进行修改
// src/lib.rs
//! # Art
//!
//! A library for modeling artistic concepts.
pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;
pub mod kinds {
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
SecondaryColor::Green
}
}
// src/main.rs
use art::PrimaryColor;
use art::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
查看文档:

可以看到,使用和查看文档都比较方便。
创建并设置crates.io账号
发布crate前,需要在crates.io创建账号并获得API token。
- 首先进入crates.io,点击右上角的Log in with Github。
- 登陆后进入账号设置页面,新建一个API token
- 运行cargo login 自己的API token命令,会将API token存储在本地~/.cargo/credentials
- 如果token被泄露,可以去创建token的地方将其删除,防止别人冒用。
- 绑定自己的邮箱,否则无法发布
在Cargo.toml文件里填写一些信息:
[package]
name = "art"#必须是在crates.io里唯一的
description = "a demo for publish crate."#简介,会出现在crate搜索数据中
license = "MIT"#提供开源许可标识,可在http://spdx.org/licenses/查看,可以指定多个,用OR隔开
version = "0.1.0"#版本号
author = "demo"#作者
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
使用cargo publish发布。 crate一旦发布,就是永久性的:该版本无法覆盖,代码无法删除。目的是让依赖该版本的项目可以一直使用。如果想发布新版本,只需要修改Cargo.toml中的version,然后重新发布即可。版本语义参考http://semver.org/
使用cargo yank从crates.io撤回版本
我们不可以删除crate之前的版本,但是可以使用cargo yank防止其他项目把它作为新的依赖,换句话说就是防止新的项目依赖该版本。已经存在的项目可继续将其作为依赖(并可*载下**)。 yank意味着:
- 所有已经产生Cargo.lock文件的项目都不会中断
- 但是任何将来生成的Cargo.lock文件都不会使用已经yank的版本
撤回命令:cargo yank --vers 1.0.1 取消撤回:cargo yank --vers 1.0.1 --undo
Cargo工作空间
Cargo工作空间:帮助管理多个相互关联且需要协同开发的crate,它是一套共享同一个Cargo.lock和输出文件夹(target)的包。
创建工作空间
有多种方式创建工作空间,例如创建含有1个二进制crate和2个library(库) crate的工作空间:
- 二进制crate中main函数依赖于其它两个library
- 其中一个库crate提供add_one函数
- 另一个库提供add_two函数
首先创建一个空文件夹,然后在里面新建Cargo.toml文件:
[workspace]
members = [
"adder",
"add-one",
"add-two",
]
然后分别执行cargo new adder,cargo new add-one --lib,cargo new add-two --lib来创建一个二进制crate和两个库crate。
//add-one/src/lib.rs
pub fn add_one(x: i32) -> i32 {
x + 1
}
//add-two/src/lib.rs
pub fn add_two(x: i32) -> i32 {
x + 2
}
//adder/src/main.rs
use add_one;
use add_two;
fn main() {
let num = 10;
println!(
"Hello, world! {} + 1 = {} {} + 2 = {}",
num,
add_one::add_one(num),
num,
add_two::add_two(num),
);
}
}
使用cargo run -p adder运行workspace中的二进制crate,同理,cargo test命令也可以用-p指定要运行哪个crate的测试。
在工作空间中依赖外部crate
工作空间只有一个Cargo.lock文件,在工作空间顶层目录。它能保证工作空间内所有crate使用的依赖版本都相同。例如我们在Cargo.toml 和 add-one/Cargo.toml 中都增加 rand crate,则 Cargo 会将其都解析为同一版本并记录到唯一的 Cargo.lock 中。使得工作空间中的所有 crate 都使用相同的依赖意味着其中的 crate 都是相互兼容的。例:
#adder/Cargo.toml
[package]
name = "adder"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
add-one = {path = "../add-one"}
add-two = {path = "../add-two"}
rand = "0.3.14"
#add-one/Cargo.toml
[package]
name = "add-one"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.3.13"
adder和add_one的Cargo.toml分别填写依赖rand的0.3.14和0.3.13,可以从下面看出我这里Cargo.lock文件里这两个工crate的依赖都被解析到了0.3.23这同一个版本上。
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "add-one"
version = "0.1.0"
dependencies = [
"rand 0.3.23",
]
[[package]]
name = "add-two"
version = "0.1.0"
[[package]]
name = "adder"
version = "0.1.0"
dependencies = [
"add-one",
"add-two",
"rand 0.3.23",
]
如果你选择向 crates.io发布工作空间中的 crate,每一个工作空间中的 crate 需要单独发布。cargo publish 命令并没有 --all 或者 -p 参数,所以必须进入每一个 crate 的目录并运行 cargo publish 来发布工作空间中的每一个 crate。
从crates.io安装二进制crate
命令:cargo install 来源:https://crates.io 限制:只能安装具有二进制目标(binary target)的crate 二进制目标:是一个可运行程序,由src/main.rs或其它被指定为二进制文件的crate生成。 通常README里有关于crate的描述:
- 是否拥有库目标(library target)
- 是否拥有二进制目标(binary target)
- 拥有二者
cargo install安装的二进制文件存放在根目录的bin文件夹。如果你是用rustup安装的Rust,没有任何自定义配置,那么二进制存放的目录是HOME/.cargo/bin,要确保该目录在环境变量 HOME /. cargo / bin ,要确保该目录在环境变量PATH中,不然安装的二进制文件无法直接运行。例:
> cargo install test_bin
Updating `sjtu` index
Downloaded test_bin v0.3.0 (registry `sjtu`)
Downloaded 1 crate (7.3 KB) in 1.04s
Installing test_bin v0.3.0
Compiling test_bin v0.3.0
Finished release [optimized] target(s) in 2.05s
Installing C:\Users\Chris\.cargo\bin\test_bin*ex.e**
Installed package `test_bin v0.3.0` (executable `test_bin*ex.e**`)
> test_bin
Output from my CLI app!
我们安装了test_bin这个binary crate,然后就可以直接用test_bin来运行这个可执行程序。
使用自定义命令扩展cargo
cargo被设计成可以使用子命令来扩展,并且无需修改cargo本身。例如$PATH中的某个二进制是cargo-something,那么我们就可以像子命令一样运行它:cargo something,这样看起来something像cargo的子命令一样。 而且这样的自定义命令可以通过cargo --list列出来。 优点:可使用cargo install来安装扩展,像内置工具一样来运行。