rust自学笔记 (rust笔记详解)

使用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生成并查看文档:

rust学习教程,rust学习资料

文档看起来也比较麻烦,需要点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);
}

查看文档:

rust学习教程,rust学习资料

可以看到,使用和查看文档都比较方便。

创建并设置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来安装扩展,像内置工具一样来运行。