发布配置
在 Rust 中 发布配置是预定义的、可定制的带有不同选项的配置,他们允许程序员更灵活地控制代码编译的多种选项。
运行 cargo build
发布时采用的 dev
配置,其更适合开发。
运行 cargo build --release
时采用 release
配置,其是更适合发布。
$ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 0.0s
$ cargo build --release
Finished release [optimized] target(s) in 0.0s
当项目的 Cargo.toml 文件中没有任何 [profile.*]
部分的时候,Cargo 会对每一个配置都采用默认设置。通过增加任何希望定制的配置对应的 [profile.*]
部分,我们可以选择覆盖任意默认设置的子集。例如,如下是 dev
和 release
配置的 opt-level
设置的默认值:
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
opt-level
设置控制 Rust 会对代码进行何种程度的优化,越高的优化级别需要更多的时间编译。我们可以选择通过在 Cargo.toml 增加不同的值来覆盖任何默认设置。
[profile.dev]
opt-level = 1
文档注释
Rust 也有特定的用于文档的注释类型,通常被称为文档注释(documentation comments),他们会生成 HTML 文档。文档注释使用三斜杠 ///
而不是两斜杆以支持 Markdown 注解来格式化文本。文档注释就位于需要文档的项的之前。示例 14-1 展示了一个 my_crate
crate 中 add_one
函数的文档注释,
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
运行 cargo doc --open
会构建当前 crate 文档的 HTML 并在浏览器中打开
示例中使用了 # Examples
Markdown 标题在 HTML 中创建了一个以 “Examples” 为标题的部分。其他一些 crate 作者经常在文档注释中使用的部分有:
- Panics:这个函数可能会
panic!
的场景。并不希望程序崩溃的函数调用者应该确保他们不会在这些情况下调用此函数。 - Errors:如果这个函数返回
Result
,此部分描述可能会出现何种错误以及什么情况会造成这些错误,这有助于调用者编写代码来采用不同的方式处理不同的错误。 - Safety:如果这个函数使用
unsafe
代码,这一部分应该会涉及到期望函数调用者支持的确保unsafe
块中代码正常工作的不变条件(invariants)。
在文档注释中增加示例代码块是一个清楚的表明如何使用库的方法,这么做还有一个额外的好处:cargo test
也会像测试那样运行文档中的示例代码
Doc-tests my_crate
running 1 test
test src/lib.rs - add_one (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
还有另一种风格的文档注释,//!
,这是包含注释的项,通常为模块整体提供文档。
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.
/// Adds one to the number given.
// --snip--
如果运行 cargo doc --open
,将会发现这些注释显示在 my_crate
文档的首页,位于 crate 中公有项列表之上,使用他们描述其容器整体的目的来帮助 crate 用户理解你的代码组织:
pub use
鉴于你的项目结构可能是一个包含多个层级的分层结构,这对于用户来说并不方便。你可以选择使用 pub use
重导出(re-export)项来使公有结构不同于私有结构。如下:假设我们创建了一个描述美术信息的库 art
。这个库中包含了一个有两个枚举 PrimaryColor
和 SecondaryColor
的模块 kinds
,以及一个包含函数 mix
的模块 utils
:
//! # 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 {
// --snip--
}
}
使用 art
crate 代码的作者不得不搞清楚 PrimaryColor
位于 kinds
模块而 mix
位于 utils
模块。为了从公有 API 中去掉 crate 的内部组织,增加 pub use
语句来重导出项到顶层结构:
//! # 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 {
// --snip--
}
pub mod utils {
// --snip--
}
现在此 crate 由 cargo doc
生成的 API 文档会在首页列出重导出的项以及其链接,这使得 PrimaryColor
和 SecondaryColor
类型和 mix
函数更易于查找,点击函数就可以直接跳转到对应属性或者函数的定义界面,使用 pub use
将类型重导出到顶级结构对于使用 crate 的人来说将会是大为不同的体验。
发布crate
在你可以发布任何 crate 之前,需要在 crates.io 上注册账号并获取一个 API token,接着使用该 API token 运行 cargo login
命令,这个命令会通知 Cargo 你的 API token 并将其储存在本地的 ~/.cargo/credentials 文件中:
cargo login 你的token
你需要在 crate 的 Cargo.toml 文件的 [package]
部分增加一些本 crate 的元信息(metadata)。
- 首先 crate 需要一个唯一的名称。一旦某个 crate 名称被使用,其他人就不能再发布这个名称的 crate 了。
license
是关于该 crate 用途的描述和用户可能在何种条款下使用该 crate 的 license。可以设置多个许可,他们使用OR
隔开
有了唯一的名称、版本号、由 cargo new
新建项目时增加的作者信息、描述和所选择的 license,已经准备好发布的项目的 Cargo.toml 文件可能看起来像这样:
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"
[dependencies]
发布 crate是永久性的。对应版本不可能被覆盖,其代码也不可能被删除,运行 cargo publish
命令可以完成你的发布:
cargo publish
Updating crates.io index
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
Finished dev [unoptimized + debuginfo] target(s) in 0.19s
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
至此,发布完成了,其他用户可以在社区下载刚刚发布的内容。
撤回版本
撤回某个版本会阻止新项目开始依赖此版本,不过所有现存此依赖的项目仍然能够下载和依赖这个版本。可以运行 cargo yank
并指定希望撤回的版本来完成这个操作:
$ cargo yank --vers 1.0.1
工作空间
Cargo 提供了一个叫工作空间(workspaces)的功能,它可以帮助我们管理多个相关的协同开发的包。
想要使用工作空间需要进行使用 Cargo.toml
文件进行配置,首先创建add 目录中,之后创建 Cargo.toml 文件,这个 Cargo.toml 文件配置了整个工作空,它以 [workspace]
部分作为开始
[workspace]
members = [
"adder",
"add_one",
]
在 add 目录运行 cargo new
新建 adder
二进制 crate,接着新生成一个叫做 add_one
的库
$ cargo new adder
Created binary (application) `adder` package
$ cargo new add_one --lib
Created library `add_one` package
现在当前目录的情况应该是
├── 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
}
现在工作空间中有了一个库 crate,让 adder
依赖库 crate add_one
。首先需要在 adder/Cargo.toml 文件中增加 add_one
作为路径依赖
[dependencies]
add_one = { path = "../add_one" }
接下来,在 adder
crate 中使用 add_one
crate 的函数 add_one
。打开 adder/src/main.rs 在顶部增加一行 use
将新 add_one
库 crate 引入作用域。
use add_one;
fn main() {
let num = 10;
println!(
"Hello, world! {} plus one is {}!",
num,
add_one::add_one(num)
);
}
在 add 目录中运行 cargo build
来构建工作空间
$ cargo build
Compiling add_one v0.1.0 (file:///projects/add/add_one)
Compiling adder v0.1.0 (file:///projects/add/adder)
Finished dev [unoptimized + debuginfo] target(s) in 0.68s
为了在顶层 add 目录运行二进制 crate,可以通过 -p
参数和包名称来 cargo run
指定工作空间中我们希望使用的包
$ cargo run -p adder
Finished dev [unoptimized + debuginfo] target(s) in 0.0s
Running `target/debug/adder`
Hello, world! 10 plus one is 11!
这样就可以做到运行 adder/src/main.rs 中的代码,其依赖 add_one
crate。工作空间只在根目录有一个 Cargo.lock,而不是在每一个 crate 目录都有 Cargo.lock,这确保了所有的 crate 都使用完全相同版本的依赖。
[dependencies]
rand = "0.8.3"
cargo install
cargo install
命令用于在本地安装和使用二进制 crate。它并不打算替换系统中的包;它意在作为一个方便 Rust 开发者们安装其他人已经在 crates.io 上共享的工具的手段。只有拥有二进制目标文件的包能够被安装。所有来自 cargo install
的二进制文件都安装到 Rust 安装根目录的 bin 文件夹中。
$ cargo install ripgrep
Updating crates.io index
Downloaded ripgrep v11.0.2
Downloaded 1 crate (243.3 KB) in 0.88s
Installing ripgrep v11.0.2
--snip--
Compiling ripgrep v11.0.2
Finished release [optimized + debuginfo] target(s) in 3m 10s
Installing ~/.cargo/bin/rg
Installed package `ripgrep v11.0.2` (executable `rg`)
之后你就可以运行 rg --help
并开始使用一个更快更 Rust 的工具来搜索文件了