wip finish ch14

pull/4/head
KaiserY 8 years ago
parent 606928c36a
commit e73ccdfca6

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -69,4 +69,11 @@
- [闭包](ch13-01-closures.md)
- [迭代器](ch13-02-iterators.md)
- [改进 I/O 项目](ch13-03-improving-our-io-project.md)
- [性能](ch13-04-performance.md)
- [性能](ch13-04-performance.md)
- [更多关于 Cargo 和 Crates.io](ch14-00-more-about-cargo.md)
- [发布配置](ch14-01-release-profiles.md)
- [将 crate 发布到 Crates.io](ch14-02-publishing-to-crates-io.md)
- [Cargo 工作空间](ch14-03-cargo-workspaces.md)
- [使用`cargo install`从 Crates.io 安装文件](ch14-04-installing-binaries.md)
- [Cargo 自定义扩展命令](ch14-05-extending-cargo.md)

@ -0,0 +1,15 @@
# 更多关于 Cargo 和 Crates.io
> [ch14-00-more-about-cargo.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-00-more-about-cargo.md)
> <br>
> commit 4f2dc564851dc04b271a2260c834643dfd86c724
目前为止本书已经使用过一些 Cargo 的功能了,不过这是最基本的那些。我们使用 Cargo 构建、运行和测试代码不过它还可以做更多。现在就让我们来了解这些其他功能。Cargo 所能做的比本章所涉及的内容还要多;作为一个完整的参考,请查看文档。
我们将要涉及到:
* 使用发布配置来自定义构建
* 将库发布到 crates.io
* 使用工作空间来组织更大的项目
* 从 crates.io 安装二进制文件
* 使用自定义的命令来扩展 Cargo

@ -0,0 +1,46 @@
## 发布配置
> [ch14-01-release-profiles.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-01-release-profiles.md)
> <br>
> commit 4f2dc564851dc04b271a2260c834643dfd86c724
Cargo 支持一个叫做**发布配置***release profiles*)的概念。这些配置控制各种代码编译参数而且彼此相互独立。在构建的输出中你已经见过了这个功能的影子:
```
$ cargo build
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
$ cargo build --release
Finished release [optimized] target(s) in 0.0 secs
```
这里的 "debug" 和 "release" 提示表明编译器在使用不同的配置。Cargo 支持四种配置:
* `dev`:用于`cargo build`
* `release`:用于`cargo build --release`
* `test`:用于`cargo test`
* `doc``cargo doc`
可以通过自定义`Cargo.toml`文件中的`[profile.*]`部分来调整这些配置的编译器参数。例如,这里是`dev`和`release`配置的默认参数:
```toml
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
```
`opt-level`设置控制 Rust 会进行何种程度的优化。这个配置的值从 0 到 3。越高的优化级别需要更多的时间。当开发时经常需要编译你通常希望能在牺牲一些代码性能的情况下编译得快一些。当准备发布时一次花费更多时间编译来换取每次都要运行的更快的编译结果将更好一些。
可以在`Cargo.toml`中覆盖这些默认设置。例如,如果你想在开发时开启一级优化:
```toml
[profile.dev]
opt-level = 1
```
这将覆盖默认的设置`0`,而现在开发构建将获得更多的优化。虽然不如发布构建,但也多少有一些。
对于每个配置的设置和其默认值的完整列表,请查看[Cargo 的 文档][cargodoc]。
[cargodoc]: http://doc.crates.io/

@ -0,0 +1,272 @@
## 将 crate 发布到 Crates.io
> [ch14-02-publishing-to-crates-io.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-02-publishing-to-crates-io.md)
> <br>
> commit c49e5ee8859f8eb8f8867cbeafbdf5b802aa5894
我们曾经在项目中增加 crates.io 上的 crate 作为依赖。也可以选择将代码分享给其他人。Crates.io 用来分发包的源代码,所以它主要用于分发开源代码。
Rust 和 Cargo 有一些帮助人们找到和使用你发布的包的功能。我们将介绍这些功能,接着讲到如何发布一个包。
### 文档注释
在第三章中,我们见到了以`//`开头的注释Rust 还有第二种注释:**文档注释***documentation comment*)。注释固然对阅读代码的人有帮助,也可以生成 HTML 代码来显式公有 API 的文档注释,这有助于那些对如何**使用** crate 有兴趣而不关心如何**实现**的人。注意只有库 crate 能生成文档,因为二进制 crate 并没有人们需要知道如何使用的公有 API。
文档注释使用`///`而不是`//`并支持 Markdown 注解。他们就位于需要文档的项的之前。如下是一个`add_one`函数的文档注释:
<span class="filename">Filename: src/lib.rs</span>
````rust
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, add_one(5));
/// # fn add_one(x: i32) -> i32 {
/// # x + 1
/// # }
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
````
<span class="caption">Listing 14-1: A documentation comment for a
function</span>
`cargo doc`运行一个由 Rust 分发的工具,`rustdoc`,来为这些注释生成 HTML 文档。可以运行`cargo doc --open`在本地尝试一下,这会构建当前状态的文档(以及 crate 的依赖)并在浏览器中打开。导航到`add_one`函数将会发现文档注释是如何渲染的。
在文档注释中增加示例代码块是一个清楚的表明如何使用库的方法。这么做还有一个额外的好处:`cargo test`也会像测试那样运行文档中的示例代码!没有什么比有例子的文档更好的了!也没有什么比不能正常工作的例子更糟的了,因为代码在编写文档时已经改变。尝试`cargo test`运行列表 14-1 中`add_one`函数的文档;将会看到如下测试结果:
```test
Doc-tests add-one
running 1 test
test add_one_0 ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
```
尝试改变示例或函数并观察`cargo test`会捕获不再能运行的例子!
还有另一种风格的文档注释,`//!`用于注释包含项的结构例如crate、模块或函数而不是其之后的项。这通常用在 crate 的根lib.rs或模块的根mod.rs来分别编写 crate 或模块整体的文档。如下是包含整个标准库的`libstd`模块的文档:
```
//! # The Rust Standard Library
//!
//! The Rust Standard Library provides the essential runtime
//! functionality for building portable Rust software.
```
### 使用`pub use`来导出合适的公有 API
第七章介绍了如何使用`mod`关键字来将代码组织进模块中,如何使用`pub`关键字将项变为公有,和如何使用`use`关键字将项引入作用域。当发布 crate 给并不熟悉其使用的库的实现的人时,就值得花时间考虑 crate 的结构对于开发和对于依赖 crate 的人来说是否同样有用。如果结构对于供其他库使用来说并不方便,也无需重新安排内部组织:可以选择使用`pub use`来重新导出一个不同的公有结构。
例如列表 14-2中我们创建了一个库`art`,其包含一个`kinds`模块,模块中包含枚举`Color`和包含函数`mix`的模块`utils`
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
//! # 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 kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// ...snip...
# SecondaryColor::Green
}
}
```
<span class="caption">Listing 14-2: An `art` library with items organized into
`kinds` and `utils` modules</span>
为了使用这个库,列表 14-3 中另一个 crate 中使用了`use`语句:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
extern crate art;
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
```
<span class="caption">Listing 14-3: A program using the `art` crate's items
with its internal structure exported</span>
使用并不需要知道`PrimaryColor`和`SecondaryColor`位于`kinds`模块中和`mix`位于`utils`模块中;这些结构对于内部组织是有帮助的,不过对于外部的观点来说没有什么意义。
为此,可以选择在列表 14-2 中增加如下`pub use`语句来将这些类型重新导出到顶级结构,如列表 14-4 所示:
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
//! # Art
//!
//! A library for modeling artistic concepts.
pub use kinds::PrimaryColor;
pub use kinds::SecondaryColor;
pub use utils::mix;
pub mod kinds {
// ...snip...
```
<span class="caption">Listing 14-4: Adding `pub use` statements to re-export
items</span>
<!-- Will add ghosting in libreoffice /Carol -->
重导出的项将会被连接和排列在 crate API 文档的头版。`art` crate 的用户仍然可以像列表 14-3 那样使用内部结构,或者使用列表 14-4 中更方便的结构,如列表 14-5 所示:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
extern crate art;
use art::PrimaryColor;
use art::mix;
fn main() {
// ...snip...
}
```
<span class="caption">Listing 14-5: Using the re-exported items from the `art`
crate</span>
<!-- Will add ghosting in libreoffice /Carol -->
创建一个有用的公有 API 结构更像一种艺术而不是科学。选择`pub use`提供了如何向用户暴露 crate 内部结构的灵活性。观察一些你所安装的 crate 的代码来看看其内部结构是否不同于公有 API。
### 在第一次发布之前
在能够发布任何 crate 之前,你需要在[crates.io]上注册一个账号并获取一个 API token。为此[访问其官网][crates.io]并使用 GitHub 账号登陆。目前 GitHub 账号是必须的,不过将来网站可能会支持其他创建账号的方法。一旦登陆之后,查看[Account Settings]页面并使用其中指定的 API key 运行`cargo login`命令,这看起来像这样:
[crates.io]: https://crates.io
[Account Settings]: https://crates.io/me
```
$ cargo login abcdefghijklmnopqrstuvwxyz012345
```
这个命令会通知 Cargo 你的 API token 并将其储存在本地的 *~/.cargo/config* 文件中。注意这个 token 是一个**秘密****secret**)并不应该与其他人共享。如果因为任何原因与他人共享了这个信息,应该立即重新生成这个 token。
### 在发布新 crate 之前
首先crate 必须有一个位移的名称。虽然在本地开发 crate 时,可以使用任何你喜欢的名字,不过[crates.io]上的 crate 名称遵守先到先得的原则分配。一旦一个 crate 名被使用,就不能被另一个 crate 所使用,所以请确认你喜欢的名字在网站上是可用的。
如果尝试发布由`cargo new`生成的 crate会出现一个警告接着是一个错误
```
$ cargo publish
Updating registry `https://github.com/rust-lang/crates.io-index`
warning: manifest has no description, license, license-file, documentation,
homepage or repository.
...snip...
error: api errors: missing or empty metadata fields: description, license.
Please see http://doc.crates.io/manifest.html#package-metadata for how to
upload metadata
```
我们可以在包的 *Cargo.toml* 文件中包含更多的信息。其中一些字段是可选的,不过描述和 license 是发布所必须的,因为这样人们才能知道 crate 是干什么的已经在什么样的条款下可以使用他们。
描述连同 crate 一起出现在搜索结果和 crate 页面中。描述通常是一两句话。`license`字段获取一个 license 标识符值,其可能的值由 Linux 基金会的[Software Package Data Exchange (SPDX)][spdx]指定。如果你想要使用一个并存在于此的 license则不使用`license`值,使用`license-file`来指定项目中包含你想要使用的 license 的文本的文件名。
关于项目所适用的 license 的指导超出了本书的范畴。很多 Rust 社区成员选择与 Rust 自身相同的 license它是一个双许可的`MIT/Apache-2.0`,这表明可以通过斜杠来分隔指定多个 license。所以一个准备好发布的项目的 *Cargo.toml* 文件看起来像这样:
[spdx]: http://spdx.org/licenses/
```toml
[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
description = "A fun game where you guess what number the computer has chosen."
license = "MIT/Apache-2.0"
[dependencies]
```
请查看[crates.io 的文档][other-metadata]中关于其他可以指定元数据的内容,他们可以帮助你的 crate 更容易被发现和使用!
[other-metadata]: http://doc.crates.io/manifest.html#package-metadata
### 发布到 Crates.io
现在我们创建了一个账号,保存了 API token为 crate 选择了一个名字,并指定了所需的元数据,我们已经准备好发布了!发布 crate 是一个特定版本的 crate 被上传并托管在 crates.io 的过程。
发布 crate 请多加小心,因为发布是**永久性的**。对应版本不能被覆盖,其代码也不可能被删除。然而,可以被发布的版本号却没有限制。
让我们运行`cargo publish`命令,这次它应该会成功因为已经指定了必须的元数据:
```
$ cargo publish
Updating registry `https://github.com/rust-lang/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 debug [unoptimized + debuginfo] target(s) in 0.19 secs
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
```
恭喜!你现在向 Rust 社区分享了代码,而且任何人都可以轻松的将你的 crate 加入他们项目的依赖。
### 发布已有 crate 的新版本
当你修改了 crate 并准备好发布新版本时,改变 *Cargo.toml* 中`version`所指定的值。请使用[语义化版本规则][semver]来根据修改的类型决定下一个版本呢号。接着运行`cargo publish`来上传新版本。
[semver]: http://semver.org/
### 使用`cargo yank`从 Crates.io 删除版本
发布版本时可能会出现意外因为这样那样的原因导致功能被破坏比如语法错误或忘记引入某些文件。对于这种情况Cargo 支持 *yanking* 一个版本。
标记一个版本的 crate 为 yank 意味着没有项目能够再开始依赖这个版本不过现存的已经依赖这个版本的项目仍然能够下载和依赖这个版本的内容。crates.io 的一个主要目的是作为一个代码的永久档案库这样能够保证所有的项目都能继续构建而允许删除一个版本违反了这个目标。本质上来说yank 意味着所有带有 *Cargo.lock* 的项目并不会被破坏,同时任何未来生成的 *Cargo.lock* 将不能使用被撤回的版本。
yank 并**不**意味着删除了任何代码。例如 yank 功能不打算删除意外上传的 secret。如果这发生了请立刻重置这些 secret。
为了 yank 一个版本的 crate运行`cargo yank`并指定需要 yank 的版本:
```
$ cargo yank --vers 1.0.1
```
也可以撤销 yank并允许项目开始依赖这个版本通过在命令中加上`--undo`
```
$ cargo yank --vers 1.0.1 --undo
```

@ -0,0 +1,174 @@
## Cargo 工作空间
> [ch14-03-cargo-workspaces.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-03-cargo-workspaces.md)
> <br>
> commit d945f6d4046f4fc3c09326213100492790aebb45
第十二章中,我们构建一个包含二进制 crate 和库 crate 的包。不过如果库 crate 继续变得更大而我们想要进一步将包拆分为多个库 crate 呢随着包增长拆分出其主要组件将是非常有帮助的。对于这种情况Cargo 提供了一个叫**工作空间***workspaces*)的功能,它可以帮助我们管理多个相关的并行开发的包。
**工作空间**是一系列的包都共享同样的 *Cargo.lock* 和输出目录。让我们使用工作空间创建一个项目,这是我们熟悉的所以就可以关注工作空间的结构了。这里有一个二进制项目它使用了两个库:一个会提供`add_one`方法而第二个会提供`add_two`方法。让我们为这个二进制项目创建一个新 crate 作为开始:
```
$ cargo new --bin adder
Created binary (application) `adder` project
$ cd adder
```
需要修改二进制包的 *Cargo.toml* 来告诉 Cargo 包`adder`是一个工作空间。再文件末尾增加如下:
```toml
[workspace]
```
类似于很多 Cargo 的功能,工作空间支持配置惯例:只要遵循这些惯例就无需再增加任何配置了。这个惯例是任何作为子目录依赖的 crate 将是工作空间的一部分。让我们像这样在 *Cargo.toml* 中的`[dependencies]`增加一个`adder` crate 的路径依赖:
```toml
[dependencies]
add-one = { path = "add-one" }
```
如果增加依赖但没有指定`path`,这将是一个不位于工作空间的正常的依赖。
接下来,在`adder`目录中生成`add-one` crate
```
$ cargo new add-one
Created library `add-one` project
```
现在`adder`目录应该有如下目录和文件:
```
├── Cargo.toml
├── add-one
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── src
└── main.rs
```
*add-one/src/lib.rs* 中增加`add_one`函数的实现:
<span class="filename">Filename: add-one/src/lib.rs</span>
```rust
pub fn add_one(x: i32) -> i32 {
x + 1
}
```
打开`adder`的 *src/main.rs* 并增加一行`extern crate`将新的`add-one`库引入作用域,并修改`main`函数来使用`add_one`函数:
```rust,ignore
extern crate add_one;
fn main() {
let num = 10;
println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num));
}
```
让我们构建一下!
```
$ cargo build
Compiling add-one v0.1.0 (file:///projects/adder/add-one)
Compiling adder v0.1.0 (file:///projects/adder)
Finished debug [unoptimized + debuginfo] target(s) in 0.68 secs
```
注意在 *adder* 目录运行`cargo build`会构建这个 crate 和 *adder/add-one* 中的`add-one` crate不过只创建一个 *Cargo.lock* 和一个 *target* 目录,他们都位于 *adder* 目录。试试你能否用相同的方式增加`add-two` crate。
假如我们想要在`add-one` crate 中使用`rand` crate。一如既往在`Cargo.toml`的`[dependencies]`部分增加这个 crate
<span class="filename">Filename: add-one/Cargo.toml</span>
```toml
[dependencies]
rand = "0.3.14"
```
如果在 *add-one/src/lib.rs* 中加上`extern crate rand;`后再运行`cargo build`,则会编译成功:
```
$ cargo build
Updating registry `https://github.com/rust-lang/crates.io-index`
Downloading rand v0.3.14
...snip...
Compiling rand v0.3.14
Compiling add-one v0.1.0 (file:///projects/adder/add-one)
Compiling adder v0.1.0 (file:///projects/adder)
Finished debug [unoptimized + debuginfo] target(s) in 10.18 secs
```
现在 *Cargo.lock* 的顶部反映了`add-one`依赖`rand`这一事实。然而即使在工作空间的某处使用了`rand`,也不能在工作空间的其他 crate 使用它,除非在对应的 *Cargo.toml* 也增加`rand`的依赖。例如,如果在顶层的`adder` crate 的 *src/main.rs* 中增加`extern crate rand;`,将会出现一个错误:
```
$ cargo build
Compiling adder v0.1.0 (file:///projects/adder)
error[E0463]: can't find crate for `rand`
--> src/main.rs:1:1
|
1 | extern crate rand;
| ^^^^^^^^^^^^^^^^^^^ can't find crate
```
为了修复这个错误,修改顶层的 *Cargo.toml* 并表明`rand`是`adder` crate 的一个依赖。
作为另一个提高,为 crate 中的`add_one::add_one`函数增加一个测试:
<span class="filename">Filename: add-one/src/lib.rs</span>
```rust
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));
}
}
```
现在在顶层的 *adder* 目录运行`cargo test`
```
$ cargo test
Compiling adder v0.1.0 (file:///projects/adder)
Finished debug [unoptimized + debuginfo] target(s) in 0.27 secs
Running target/debug/adder-f0253159197f7841
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
等等,零个测试?我们不是刚增加了一个吗?如果我们观察输出,就不难发现在工作空间中的`cargo test`只运行顶层 crate 的测试。为了运行其他 crate 的测试,需要使用`-p`参数来表明我们希望与逆行测试包的测试:
```
$ cargo test -p add-one
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
Running target/debug/deps/add_one-abcabcabc
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
Doc-tests add-one
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
类似的,如果选择将工作空间发布到 crates.io其中的每一个包都需要单独发布。
随着项目增长,考虑使用工作空间:每一个更小的组件比一大块代码要容易理解。将 crate 保持在工作空间中易于协调他们的改变,如果他们一起运行并经常需要同时被修改的话。

@ -0,0 +1,21 @@
## 使用`cargo install`从 Crates.io 安装文件
> [ch14-04-installing-binaries.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-04-installing-binaries.md)
> <br>
> commit 4f2dc564851dc04b271a2260c834643dfd86c724
`cargo install`命令用于在本地安装和使用二进制 crate。它并不打算替换系统中的包它意在作为一个方便 Rust 开发者安装他人在 crates.io 共享的工具的手段。只有有二进制目标文件的包能够安装,而且所有二进制文件都被安装到 Rust 安装根目录的 *bin* 文件夹中。如果你使用 *rustup.rs* 安装的 Rust 且没有自定义任何配置,这将是`$HOME/.cargo/bin`。将这个目录添加到`$PATH`环境变量中就能够运行通过`cargo install`安装的程序了。
例如,第十二章提到的叫做`ripgrep`的用于搜索文件的`grep`的 Rust 实现。如果想要安装`ripgrep`,可以运行如下:
```
$ cargo install ripgrep
Updating registry `https://github.com/rust-lang/crates.io-index`
Downloading ripgrep v0.3.2
...snip...
Compiling ripgrep v0.3.2
Finished release [optimized + debuginfo] target(s) in 97.91 secs
Installing ~/.cargo/bin/rg
```
最后一行输出展示了安装的二进制文件的位置和名称,在这里`ripgrep`被命名为`rg`。只要你像上面提到的那样将安装目录假如`$PATH`,就可以运行`rg --help`并开始使用一个更快更 Rust 的工具来搜索文件了!

@ -0,0 +1,11 @@
## Cargo 自定义扩展命令
> [ch14-05-extending-cargo.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-05-extending-cargo.md)
> <br>
> commit 4f2dc564851dc04b271a2260c834643dfd86c724
Cargo 被设计为可扩展的,通过新的子命令而无须修改 Cargo 自身。如果`$PATH`中有类似`cargo-something`的二进制文件,就可以通过`cargo something`来像 Cargo 子命令一样运行它。像这样的自定义命令也可以运行`cargo --list`来展示出来,通过`cargo install`向 Cargo 安装扩展并可以如内建 Cargo 工具那样运行他们是很方便的!
## 总结
通过 Cargo 和 crates.io 来分享代码是使得 Rust 生态环境可以用于许多不同的任务的重要组成部分。Rust 的标准库是小而稳定的,不过 crate 易于分享和使用,并采用一个不同语言自身的时间线来提供改进。不要羞于在 crates.io 上共享对你有用的代码;因为它很有可能对别人也很有用!
Loading…
Cancel
Save