30、Rust 包管理器 cargo

Rust 内置了一个包管理器 cargo。它会随着 Rust 的安装而安装。

cargo 类似于 Python 中的 pip 或 Ruby 中的 RubyGems 或 Node.js 中的 NPM。

当然了,cargo 不仅仅是一个包管理器,它还是 Rust 的项目管理利器。

检查 cargo 是否安装和安装的版本

打开终端或命令行提示符或 Shell,输入下面的命令然后回车

cargo --version

如果已经安装,则输出结果类似于

cargo 1.35.0

cargo 包管理器的版本和 Rust 语言是同步的。

cargo 的帮助信息

如果想要查看 cargo 的帮助信息或查看 cargo 提供了哪些命令和功能,可以在 终端 中输入 cargo 或 cargo -h 然后回车

输出结果类似于

Rust's package manager

USAGE:
    cargo [OPTIONS] [SUBCOMMAND]

OPTIONS:
    -V, --version           Print version info and exit
        --list              List installed commands
        --explain `<CODE>`    Run rustc --explain CODE
    -v, --verbose           Use verbose output (-vv very verbose/build.rs output)
    -q, --quiet             No output printed to stdout
        --color <WHEN>      Coloring: auto, always, never
        --frozen            Require Cargo.lock and cache are up to date
        --locked            Require Cargo.lock is up to date
    -Z <FLAG>...            Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
    -h, --help              Prints help information

Some common cargo commands are (see all commands with --list):
    build       Compile the current package
    check       Analyze the current package and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this package's and its dependencies' documentation
    new         Create a new cargo package
    init        Create a new cargo package in an existing directory
    run         Run a binary or example of the local package
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this package to the registry
    install     Install a Rust binary. Default location is $HOME/.cargo/bin
    uninstall   Uninstall a Rust binary

See 'cargo help <command>' for more information on a specific command.

cargo 提供的命令

正如上面 cargo 帮助信息中所描述的那样,如果我们想要查看 cargo 提供的所有命令,可以直接在终端里输入

cargo --list

输出结果如下

Installed Commands:
    bench                Execute all benchmarks of a local package
    build                Compile a local package and all of its dependencies
    check                Check a local package and all of its dependencies for errors
    clean                Remove artifacts that cargo has generated in the past
    clippy-preview       Checks a package to catch common mistakes and improve your Rust code.
    doc                  Build a package's documentation
    fetch                Fetch dependencies of a package from the network
    fix                  Automatically fix lint warnings reported by rustc
    generate-lockfile    Generate the lockfile for a package
    git-checkout         Checkout a copy of a Git repository
    init                 Create a new cargo package in an existing directory
    install              Install a Rust binary. Default location is $HOME/.cargo/bin
    locate-project       Print a JSON representation of a Cargo.toml file's location
    login                Save an api token from the registry locally. If token is not specified, it will be read from stdin.
    metadata             Output the resolved dependencies of a package, the concrete used versions including overrides, in machine-readable format
    new                  Create a new cargo package at <path>
    owner                Manage the owners of a crate on the registry
    package              Assemble the local package into a distributable tarball
    pkgid                Print a fully qualified package specification
    publish              Upload a package to the registry
    read-manifest        Print a JSON representation of a Cargo.toml manifest.
    run                  Run a binary or example of the local package
    rustc                Compile a package and all of its dependencies
    rustdoc              Build a package's documentation, using specified custom flags.
    search               Search packages in crates.io
    test                 Execute all unit and integration tests and build examples of a local package
    uninstall            Remove a Rust binary
    update               Update dependencies as recorded in the local lock file
    verify-project       Check correctness of crate manifest
    version              Show version information
    yank                 Remove a pushed crate from the index

命令很多,我们就不逐一介绍了,挑几个常用的命令介绍下

命令 说明
cargo build 编译当前项目
cargo check 分析当前项目并报告项目中的错误,但不会编译任何项目文件
cargo run 编译并运行文件 src/main.rs
cargo clean 移除当前项目下的 target 目录及目录中的所有子目录和文件
cargo update 更新当前项目中的 Cargo.lock 文件列出的所有依赖
cargo new 在当前目录下新建一个 cargo 项目

如果你对某个命令不甚熟悉,可以直接使用 cargo help <command> 语法显示命令的帮助信息。

比如要详细了解 new 命令,可以直接输入 cargo help new,输出结果如下

cargo-new 
Create a new cargo package at <path>

USAGE:
    cargo new [OPTIONS] <path>

OPTIONS:
    -q, --quiet                  No output printed to stdout
        --registry <REGISTRY>    Registry to use
        --vcs <VCS>              Initialize a new repository for the given version control system (git, hg, pijul, or
                                 fossil) or do not initialize any version control at all (none), overriding a global
                                 configuration. [possible values: git, hg, pijul, fossil, none]
        --bin                    Use a binary (application) template [default]
        --lib                    Use a library template
        --edition <YEAR>         Edition to set for the crate generated [possible values: 2015, 2018]
        --name <NAME>            Set the resulting package name, defaults to the directory name
    -v, --verbose                Use verbose output (-vv very verbose/build.rs output)
        --color <WHEN>           Coloring: auto, always, never
        --frozen                 Require Cargo.lock and cache are up to date
        --locked                 Require Cargo.lock is up to date
    -Z <FLAG>...                 Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
    -h, --help                   Prints help information

ARGS:
    <path>  

cargo 创建 Rust 项目

作为包管理器,cargo 可以帮助我们下载第三方库。但这仅仅是 cargo 功能的冰山一角。

我们还可以使用 cargo 来构建自己的 ,然后发布到 Cargo 的官方仓库中。

cargo 可以创建两种类型的项目:可执行的二进制程序

如果要创建一个 可执行的二进制程序,可以使用下面的 cargo new 命令创建项目

cargo new project_name --bin

如果要创建一个 ,则可以使用下面的 cargo new 命令。

cargo new project_name --lib

范例: 使用 cargo 创建并构建一个完整的二进制可执行程序项目

创建项目、安装依赖、编译项目是 cargo 作为包管理器的三个最重要的功能。

下面我们就以一个简单的游戏:猜数字 来演示下如何使用 cargo 创建并编译项目。

一、 创建项目目录

打开终端或命令行提示符或 Shell 并进入到你想放项目的目录下。

然后输入命令 cargo new guess-game-app --bin,如果不出意外就会输出下面的提示

[www.ddkk.com]$ cargo new guess-game-app --bin
     Created binary (application) guess-game-app package

出现上面的提示说明项目创建成功,同时该命令会在当前目录下创建一个新的目录 guess-game-app 并创建一些必要的文件

[www.ddkk.com]$ tree guess-game-app/
guess-game-app/
├── Cargo.toml
└── src
    └── main.rs

通过上面的篇幅可知:cargo new 命令用于创建一个新项目,--bin 选项用于指示当前项目是一个 可执行的二进制程序 项目。

在Cargo 中,通常把一个项目称之为 crates,but 我也不理解为啥...

Rust 官方为 cargo 包管理器提供了中央托管网站。网站地址为 https://crates.io/。 我们可以从该网站上找到一些我们需要的第三方库或者一些有用的第三方项目。

二、添加项目需要的第三方依赖库

我们的猜数字 游戏需要生成 随机数。 但是 Rust 语言核心和 Rust 标准库都没有提供生成随机数的的方法或结构体。

我们只能借助于 https://crates.io/ 上其它开发者提供的第三方库或 crates。

我们可以打开网站 crates.io 并在顶部的搜索中输入 rand 然后回车来查找第三方随机数生成库。

从搜索的结果来看,由很多和随机数生成的相关库,不过我们只使用 rand。

点击搜索结果中的 rand 会跳转到 https://crates.io/crates/rand

下图是我们需要的 随机数生成库 rand 的基本信息截图。

 

了解了rand 的基本信息后,我们就可以修改 Cargo.toml 添加 rand 依赖了。

准确的说就是在 [dependencies] 节中添加 rand = "0.6.5"。

编辑完成后的文件内容如下

[package]
name = "guess-game-app"
version = "0.1.0"
authors = ["语飞 <noreply@ddkk.cn>"]
edition = "2018"

[dependencies]
rand = "0.6.5"

三、 先预编译项目

对于Rust / C / C++ 这种静态语言,先预编译一下应该是一种习惯。

因为预编译的时候会告诉我们项目配置是否正确,同时会下载第三方库,这样就可以 自动提示 了。

使用cargo 创建的项目,我们可以在终端里输入 cargo build 来预编译下项目。

输出一般如下

    Updating crates.io index
  Downloaded rand v0.6.5
  Downloaded libc v0.2.58
  Downloaded rand_core v0.4.0
  Downloaded rand_hc v0.1.0
  Downloaded rand_chacha v0.1.1
  Downloaded rand_isaac v0.1.1
  Downloaded rand_jitter v0.1.4
  Downloaded rand_os v0.1.3
  Downloaded rand_xorshift v0.1.1
  Downloaded rand_pcg v0.1.2
  Downloaded autocfg v0.1.4
  Downloaded rand_core v0.3.1
   Compiling libc v0.2.58
   Compiling autocfg v0.1.4
   Compiling rand_core v0.4.0
   Compiling rand_core v0.3.1
   Compiling rand_isaac v0.1.1
   Compiling rand_xorshift v0.1.1
   Compiling rand_hc v0.1.0
   Compiling rand_pcg v0.1.2
   Compiling rand_chacha v0.1.1
   Compiling rand v0.6.5
   Compiling rand_os v0.1.3
   Compiling rand_jitter v0.1.4
   Compiling guess-game-app v0.1.0 (/Users/penglei/Downloads/guess-game-app)
    Finished dev [unoptimized + debuginfo] target(s) in 45.77s

从预编译输出的信息中我们可以看到:rand 第三方库和相关的依赖都会自动被下载。

四、 理解 猜数字 游戏逻辑

动手码代码之前,我们先来分析下 猜数字 游戏的游戏逻辑。

这是一种良好的编程习惯。

1、 游戏开始时先随机生成一个数字N;
2、 然后输出一些信息提示用户,并让用户猜并输入生成的数字N是多少;
3、 如果用户输入的数字小于随机数,则提示用户Toolow然后让用户继续猜;
4、 如果用户输入的数字大于随机数,则提示用于Toohigh然后让用户继续猜;
5、 如果用户输入的数字正好是随机数,则游戏结束并输出Yougoit..;

五、 修改 main.rs 文件完善游戏逻辑

猜数字 游戏逻辑很简单,前面我们已经详细的分析过了,接下来我们只要实现上面的逻辑即可。

代码我们就不做做介绍了,直接复制粘贴就好

use std::io;
extern crate rand; // 导入当前项目下的 rand 第三方库

use rand::random;
fn get_guess() -> u8 {
   loop {
      println!("Input guess") ;
      let mut guess = String::new();
      io::stdin().read_line(&mut guess)
         .expect("could not read from stdin");
      match guess.trim().parse::<u8>(){ // 需要去除输入首尾的空白
         Ok(v) => return v,
         Err(e) => println!("could not understand input {}",e)
      }
   }
}
fn handle_guess(guess:u8,correct:u8)-> bool {
   if guess < correct {
      println!("Too low");
      false

   } else if guess> correct {
      println!("Too high");
      false
   } else {
      println!("You go it ..");
      true
   }
}
fn main() {
   println!("Welcome to no guessing game");

   let correct:u8 = random();
   println!("correct value is {}",correct);
   loop {
      let guess = get_guess();
      if handle_guess(guess,correct){
         break;
      }
   }
}

六、编译项目并运行可执行文件

我们可以在 终端 中输入命令 cargo run 编译并运行我们的猜数字游戏。

如果没有出现任何错误,那么我们就可以简单的来玩几盘,哈哈

   Compiling guess-game-app v0.1.0 (/Users/penglei/Downloads/guess-game-app)
    Finished dev [unoptimized + debuginfo] target(s) in 0.67s
     Running target/debug/guess-game-app
Welcome to no guessing game
correct value is 145
Input guess
20
Too low
Input guess
100
Too low
Input guess
97
Too low
Input guess
145
You go it ..

哈哈,其实我们是有点作弊嫌疑,因为不提示结果,要猜中得很长的逻辑