文档注释,发布crate包
目前为止我们只使用过 Cargo
构建、运行和测试代码这些最基本的功能,不过它还可以做到更多官方文档。
在 Rust
中发布配置(release profiles)
是预定义的、可定制的带有不同选项的配置,他们允许程序员更灵活地控制代码编译的多种选项。每一个配置都彼此相互独立。
Cargo
有两个主要的配置:运行 cargo build
时采用的dev
配置和运行cargo build --release
的 release
配置。dev
配置被定义为开发时的好的默认配置,release
配置则有着良好的发布构建的默认配置。
这些配置名称可能很眼熟,因为它们出现在构建的输出中:
$ cargo build
Compiling cargo1 v0.1.0 (/rsut/cargo1)
Finished dev [unoptimized + debuginfo] target(s) in 0.67s
$ cargo build --release
Compiling cargo1 v0.1.0 (/rsut/cargo1)
Finished release [optimized] target(s) in 0.11s
构建输出中的 dev
和 release
表明编译器在使用不同的配置。
当项目的 Cargo.toml
文件中没有显式增加任何 [profile.*]
部分的时候,Cargo
会对每一个配置都采用默认设置。通过增加任何希望定制的配置对应的[profile.*]
部分,我们可以选择覆盖任意默认设置的子集。例如,如下是 dev
和release
配置的 opt-level
设置的默认值:
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
opt-level
设置控制 Rust
会对代码进行何种程度的优化。这个配置的值从 0
到 3
。越高的优化级别需要更多的时间编译,所以如果你在进行开发并经常编译,可能会希望在牺牲一些代码性能的情况下减少优化以便编译得快一些。因此 dev
的 opt-level
默认为0
。当你准备发布时,花费更多时间在编译上则更好。只需要在发布模式编译一次,而编译出来的程序则会运行很多次,所以发布模式用更长的编译时间换取运行更快的代码。这正是为什么 release
配置的 opt-level
默认为 3
。
我们可以选择通过在 Cargo.toml
增加不同的值来覆盖任何默认设置。比如,如果我们想要在开发配置中使用级别 1
的优化,则可以在 Cargo.toml
中增加这两行:
[profile.dev]
opt-level = 1
这会覆盖默认的设置 0
。现在运行cargo build
时,Cargo
将会使用 dev
的默认配置加上定制的opt-level
。因为 opt-level
设置为1
,Cargo
会比默认进行更多的优化,但是没有发布构建那么多。
文档注释使用三斜杠///
而不是两斜杆以支持 Markdown
注解来格式化文本。文档注释就位于需要文档的项的之前,新建项目:
$ cargo new learn_cratel
$ cd learn_cratel
$ cargo new mylib --lib
打开mylib
的lib.rs
给默认的add
函数增加文档注释:
/// 两个usize相加
pub fn add(left: usize, right: usize) -> usize {
left + right
}
可以运行cargo doc
来生成这个文档注释的 HTML
文档。这个命令运行由Rust
分发的工具 rustdoc
并将生成的HTML
文档放入 target/doc
目录。
为了方便起见,运行 cargo doc --open
会构建当前 crate
文档(同时还有所有 crate
依赖的文档)的 HTML
并在浏览器中打开。导航到 add
函数将会发现文档注释的文本是如何渲染的:
$ cd mylib
$ cargo doc --open
现在我们只是简单加了一个标题,还可以继续丰富一下文档注释:
/// Add two numbers together
/// # Example
/// ```
/// let left = 1;
/// let right = 2;
/// assert_eq!(3, mylib(left,right));
/// ```
pub fn add(left: usize, right: usize) -> usize {
left + right
}
这里,我们提供了一个 add
函数工作的描述,接着开始了一个标题为 Example
的部分,和展示如何使用 add
函数的代码。
在文档注释中增加示例代码块是一个清楚的表明如何使用库的方法,这么做还有一个额外的好处:cargo test
也会像测试那样运行文档中的示例代码!没有什么比有例子的文档更好的了,但最糟糕的莫过于写完文档后改动了代码,而导致例子不能正常工作。尝试 cargo test
运行add_
函数的文档;应该在测试结果中看到像这样的部分:
Doc-tests mylib
running 1 test
test src/lib.rs - add (line 3) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.18s
现在尝试改变函数或例子来使例子中的 assert_eq!
产生 panic
。再次运行 cargo test
,你将会看到文档测试捕获到了例子与代码不再同步!
文档注释风格 //!
为包含注释的项,而不是位于注释之后的项增加文档。这通常用于crate
根文件(通常是 src/lib.rs
)或模块的根文件为 crate
或模块整体提供文档:
//! # My Crate
//!
//! `learn_cratel` is a collection of utilites to make
/// Add two numbers together
/// # Example
/// ```
/// let left = 1;
/// let right = 2;
/// assert_eq!(3, mylib::add(left,right));
/// ```
pub fn add(left: usize, right: usize) -> usize {
left + right
}
注意//!
的最后一行之后没有任何代码。因为他们以 //!
开头而不是 ///
,这是属于包含此注释的项而不是注释之后项的文档。在这个情况下时 src/lib.rs
文件,也就是 crate
根文件。这些注释描述了整个 crate
。
如果运行 cargo doc --open
,将会发现这些注释显示在 learn_cratel
文档的首页,位于 crate
中公有项列表之上:
位于项之中的文档注释对于描述crate
和模块特别有用。使用他们描述其容器整体的目的来帮助 crate
用户理解你的代码组织。
我们曾经在项目中使用 crates.io
上的包作为依赖,不过你也可以通过发布自己的包来向他人分享代码。crates.io
用来分发包的源代码,所以它主要托管开源代码。
在你可以发布任何 crate
之前,需要在crates.io 上注册账号并获取一个API token
。为此,访问位于 crates.io 的首页并使用 GitHub
账号登录。(目前 GitHub
账号是必须的,不过将来该网站可能会支持其他创建账号的方法)一旦登录之后,查看位于 https://crates.io/me/
的账户设置页面并获取 API token
。接着使用该API token
运行 cargo login
命令,像这样:
$ cargo login sdfswfdwerwfd3erasdsa31564rewfdew
这个命令会通知 Cargo
你的 API token
并将其储存在本地的 ~/.cargo/credentials
文件中。注意这个 token
是一个秘密(secret)
且不应该与其他人共享。
现在我们创建了一个账号,保存了API token
。发布 crate
会上传特定版本的 crate
到crates.io
以供他人使用。
发布 crate
时请多加小心,因为发布是永久性的(permanent)
。对应版本不可能被覆盖,其代码也不可能被删除。crates.io
的一个主要目标是作为一个存储代码的永久文档服务器,这样所有依赖 crates.io
中的 crate
的项目都能一直正常工作。而允许删除版本没办法达成这个目标。然而,可以被发布的版本号却没有限制。
运行 cargo publish
命令。我们会得到一个错误:
Caused by:
the remote server responded with an error: missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for how to upload metadata
这个错误是因为我们缺少一些关键信息:description
,license
修改Cargo.toml
增加配置:
description = "This is a test project"
license = "MIT OR Apache-2.0"
再次运行cargo publish
命令。这次它应该会成功:
$ cargo publish
Updating crates.io index
warning: manifest has no documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
Packaging mylib-hekang v0.1.0 (/rsut/learn_cratel/mylib)
Verifying mylib-hekang v0.1.0 (/rsut/learn_cratel/mylib)
Compiling mylib-hekang v0.1.0 (/rsut/learn_cratel/mylib/target/package/mylib-hekang-0.1.0)
Finished dev [unoptimized + debuginfo] target(s) in 0.84s
Packaged 3 files, 1.3KiB (901.0B compressed)
Uploading mylib-hekang v0.1.0 (/rsut/learn_cratel/mylib)
Updating crates.io index
Waiting on `mylib-hekang` to propagate to crates.io index (ctrl-c to wait asynchronously)
Updating crates.io index
Updating crates.io index
Updating crates.io index
Updating crates.io index
Updating crates.io index
恭喜!你现在向 Rust
社区分享了代码,而且任何人都可以轻松的将你的 crate
加入他们项目的依赖。
当你修改了 crate
并准备好发布新版本时,改变Cargo.toml
中 version
所指定的值。请使用 语义化版本规则 来根据修改的类型决定下一个版本号。接着运行cargo publish
来上传新版本。
虽然你不能删除之前版本的 crate
,但是可以阻止任何将来的项目将他们加入到依赖中。这在某个版本因为这样或那样的原因被破坏的情况很有用。对于这种情况,Cargo
支持 撤回(yanking)
某个版本。
撤回某个版本会阻止新项目依赖此版本,不过所有现存此依赖的项目仍然能够下载和依赖这个版本。从本质上说,撤回意味着所有带有 Cargo.lock
的项目的依赖不会被破坏,同时任何新生成的 Cargo.lock
将不能使用被撤回的版本。
为了撤回一个版本的 crate
,在之前发布crate
的目录运行 cargo yank
并指定希望撤回的版本。例如,如果我们发布了一个名为 mylib-hekang
的 crate
的0.1.0
版本并希望撤回它,在 mylib-hekang
项目目录运行:
$ cargo yank --vers 0.1.0
Updating crates.io index
Yank mylib-hekang@0.1.0
也可以撤销撤回操作,并允许项目可以再次开始依赖某个版本,通过在命令上增加 --undo
:
$ cargo yank --vers 0.1.0 --undo
Updating crates.io index
Unyank mylib-hekang@0.1.0
撤回并没有删除任何代码。举例来说,撤回功能并不能删除不小心上传的秘密信息。如果出现了这种情况,请立即重新设置这些秘密信息。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!