pull/737/head
sunface 3 years ago
commit d06e5d0094

@ -134,7 +134,7 @@
- [编写测试及控制执行](test/write-tests.md) - [编写测试及控制执行](test/write-tests.md)
- [单元测试和集成测试](test/unit-integration-test.md) - [单元测试和集成测试](test/unit-integration-test.md)
- [断言 assertion](test/assertion.md) - [断言 assertion](test/assertion.md)
- [用 Github Actions 进行持续集成](test/ci.md) - [用 GitHub Actions 进行持续集成](test/ci.md)
- [基准测试 benchmark](test/benchmark.md) - [基准测试 benchmark](test/benchmark.md)
- [Cargo 使用指南](cargo/intro.md) - [Cargo 使用指南](cargo/intro.md)

@ -11,7 +11,7 @@ Rust语言真的好连续六年成为全世界最受欢迎的语言、没有G
如果看到这里,大家觉得这本书的介绍并没有吸引到你,不要立即放弃,强烈建议读一下[进入 Rust 编程世界](https://course.rs/into-rust.html),那里会有不一样的精彩。 如果看到这里,大家觉得这本书的介绍并没有吸引到你,不要立即放弃,强烈建议读一下[进入 Rust 编程世界](https://course.rs/into-rust.html),那里会有不一样的精彩。
> 本书完全开源,所有的文档内容都在 `Github` 上,至于里面还藏有什么秘密,大家点击右上角自行发现吧 > 本书完全开源,所有的文档内容都在 `GitHub` 上,至于里面还藏有什么秘密,大家点击右上角自行发现吧
> >
> 小秘密一: 你们可能会好奇,这本书到底与其它 Rust 书籍有[哪些不同](https://github.com/sunface/rust-course#教程简介) > 小秘密一: 你们可能会好奇,这本书到底与其它 Rust 书籍有[哪些不同](https://github.com/sunface/rust-course#教程简介)
@ -26,7 +26,7 @@ Rust语言真的好连续六年成为全世界最受欢迎的语言、没有G
同时社区还提供了一个优质的公众号: `studyrust`,里面的文章是由 [Rustt](https://rustt.org) 翻译组提供,搬运自国外优秀的 Rust 技术文章、学习资料、新闻资讯等。 同时社区还提供了一个优质的公众号: `studyrust`,里面的文章是由 [Rustt](https://rustt.org) 翻译组提供,搬运自国外优秀的 Rust 技术文章、学习资料、新闻资讯等。
- 社区官网:[https://studyrust.org](https://studyrust.org),正在建设中,暂时跳转到 Github 组织首页 - 社区官网:[https://studyrust.org](https://studyrust.org),正在建设中,暂时跳转到 GitHub 组织首页
- QQ交流群: 1009730433 - QQ交流群: 1009730433
- 微信公众号:`studyrust` - 微信公众号:`studyrust`

@ -311,7 +311,7 @@ hello_macro
由于过程宏所在的包跟我们的项目紧密相连,因此将它放在项目之中。现在,问题又来了,该如何在项目的 `src/main.rs` 中引用 `hello_macro_derive` 包的内容? 由于过程宏所在的包跟我们的项目紧密相连,因此将它放在项目之中。现在,问题又来了,该如何在项目的 `src/main.rs` 中引用 `hello_macro_derive` 包的内容?
方法有两种,第一种是将 `hello_macro_derive` 发布到 `crates.io``github` 中,就像我们引用的其它依赖一样;另一种就是使用相对路径引入的本地化方式,修改 `hello_macro/Cargo.toml` 文件添加以下内容: 方法有两种,第一种是将 `hello_macro_derive` 发布到 `crates.io``GitHub` 中,就像我们引用的其它依赖一样;另一种就是使用相对路径引入的本地化方式,修改 `hello_macro/Cargo.toml` 文件添加以下内容:
```toml ```toml
[dependencies] [dependencies]

@ -105,6 +105,6 @@ error: a bin target must be available for `cargo run`
- 基准性能测试 `benchmark` 文件:`benches` 目录下 - 基准性能测试 `benchmark` 文件:`benches` 目录下
- 项目示例:`examples` 目录下 - 项目示例:`examples` 目录下
这种目录结构基本上是 Rust 的标准目录结构,在 `github` 的大多数项目上,你都将看到它的身影。 这种目录结构基本上是 Rust 的标准目录结构,在 `GitHub` 的大多数项目上,你都将看到它的身影。
理解了包的概念,我们再来看看构成包的基本单元:模块。 理解了包的概念,我们再来看看构成包的基本单元:模块。

@ -6,7 +6,7 @@
## 使用 if 来做分支控制 ## 使用 if 来做分支控制
> if else 无处不在 - 鲁迅 > if else 无处不在 -- 鲁迅
但凡你能找到一门编程语言没有 `if else`,那么一定更要反馈给鲁迅,反正不是我说的:) 总之,只要你拥有其它语言的编程经验,就一定会有以下认知:`if else` **表达式**根据条件执行不同的代码分支: 但凡你能找到一门编程语言没有 `if else`,那么一定更要反馈给鲁迅,反正不是我说的:) 总之,只要你拥有其它语言的编程经验,就一定会有以下认知:`if else` **表达式**根据条件执行不同的代码分支:
@ -56,7 +56,7 @@ error[E0308]: if and else have incompatible types
found type `&str` found type `&str`
``` ```
#### 使用 else if 来处理多重条件 ## 使用 else if 来处理多重条件
可以将 `else if``if`、`else` 组合在一起实现更复杂的条件分支判断: 可以将 `else if``if`、`else` 组合在一起实现更复杂的条件分支判断:
@ -82,20 +82,20 @@ fn main() {
如果代码中有大量的 `else if ` 会让代码变得极其丑陋,不过不用担心,下一章的 `match` 专门用以解决多分支模式匹配的问题。 如果代码中有大量的 `else if ` 会让代码变得极其丑陋,不过不用担心,下一章的 `match` 专门用以解决多分支模式匹配的问题。
## 循环控制 # 循环控制
循环无处不在,上到数钱,下到数年,你能想象的很多场景都存在循环,因此它也是流程控制中最重要的组成部分之一。 循环无处不在,上到数钱,下到数年,你能想象的很多场景都存在循环,因此它也是流程控制中最重要的组成部分之一。
在 Rust 语言中有三种循环方式:`for`、`while` 和 `loop`,其中 `for` 循环是 Rust 循环王冠上的明珠。 在 Rust 语言中有三种循环方式:`for`、`while` 和 `loop`,其中 `for` 循环是 Rust 循环王冠上的明珠。
#### for 循环 ## for 循环
`for` 循环是 Rust 的大杀器: `for` 循环是 Rust 的大杀器:
```rust ```rust
fn main() { fn main() {
for i in 1..=5 { for i in 1..=5 {
println!("{}",i); println!("{}", i);
} }
} }
``` ```
@ -140,10 +140,10 @@ for item in &mut collection {
```rust ```rust
fn main() { fn main() {
let a = [4,3,2,1]; let a = [4, 3, 2, 1];
// `.iter()` 方法把 `a` 数组变成一个迭代器 // `.iter()` 方法把 `a` 数组变成一个迭代器
for (i,v) in a.iter().enumerate() { for (i, v) in a.iter().enumerate() {
println!("第{}个元素是{}",i+1,v); println!("第{}个元素是{}", i + 1, v);
} }
} }
``` ```
@ -183,7 +183,7 @@ for item in collection {
由于 `for` 循环无需任何条件限制,也不需要通过索引来访问,因此是最安全也是最常用的,通过与下面的 `while` 的对比,我们能看到为什么 `for` 会更加安全。 由于 `for` 循环无需任何条件限制,也不需要通过索引来访问,因此是最安全也是最常用的,通过与下面的 `while` 的对比,我们能看到为什么 `for` 会更加安全。
#### `continue` ## `continue`
使用 `continue` 可以跳过当前当次的循环,开始下次的循环: 使用 `continue` 可以跳过当前当次的循环,开始下次的循环:
@ -192,7 +192,7 @@ for item in collection {
if i == 2 { if i == 2 {
continue; continue;
} }
println!("{}",i); println!("{}", i);
} }
``` ```
@ -203,7 +203,7 @@ for item in collection {
3 3
``` ```
#### `break` ## `break`
使用 `break` 可以直接跳出当前整个循环: 使用 `break` 可以直接跳出当前整个循环:
@ -212,7 +212,7 @@ for item in collection {
if i == 2 { if i == 2 {
break; break;
} }
println!("{}",i); println!("{}", i);
} }
``` ```
@ -222,7 +222,7 @@ for item in collection {
1 1
``` ```
#### while 循环 ## while 循环
如果你需要一个条件来循环,当该条件为 `true` 时,继续循环,条件为 `false`,跳出循环,那么 `while` 就非常适用: 如果你需要一个条件来循环,当该条件为 `true` 时,继续循环,条件为 `false`,跳出循环,那么 `while` 就非常适用:
@ -262,7 +262,7 @@ fn main() {
if n > 5 { if n > 5 {
break break
} }
println!("{}",n); println!("{}", n);
n+=1; n+=1;
} }
@ -317,7 +317,7 @@ fn main() {
可以看出,`for` 并不会使用索引去访问数组,因此更安全也更简洁,同时避免 `运行时的边界检查`,性能更高。 可以看出,`for` 并不会使用索引去访问数组,因此更安全也更简洁,同时避免 `运行时的边界检查`,性能更高。
#### loop 循环 ## loop 循环
对于循环而言,`loop` 循环毋庸置疑,是适用面最高的,它可以适用于所有循环场景(虽然能用,但是在很多场景下, `for``while` 才是最优选择),因为 `loop` 就是一个简单的无限循环,你可以在内部实现逻辑通过 `break` 关键字来控制循环何时结束。 对于循环而言,`loop` 循环毋庸置疑,是适用面最高的,它可以适用于所有循环场景(虽然能用,但是在很多场景下, `for``while` 才是最优选择),因为 `loop` 就是一个简单的无限循环,你可以在内部实现逻辑通过 `break` 关键字来控制循环何时结束。
@ -368,8 +368,6 @@ fn main() {
- **break 可以单独使用,也可以带一个返回值**,有些类似 `return` - **break 可以单独使用,也可以带一个返回值**,有些类似 `return`
- **loop 是一个表达式**,因此可以返回一个值 - **loop 是一个表达式**,因此可以返回一个值
## 课后练习 ## 课后练习
> [Rust By Practice](https://zh.practice.rs/flow-control.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。 > [Rust By Practice](https://zh.practice.rs/flow-control.html),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice)。

@ -9,7 +9,7 @@
## 是否上传本地的 `Cargo.lock` ## 是否上传本地的 `Cargo.lock`
当本地开发时,`Cargo.lock` 自然是非常重要的,但是当你要把项目上传到 `Git` 时,例如 `Github`,那是否上传 `Cargo.lock` 就成了一个问题。 当本地开发时,`Cargo.lock` 自然是非常重要的,但是当你要把项目上传到 `Git` 时,例如 `GitHub`,那是否上传 `Cargo.lock` 就成了一个问题。
关于是否上传,有如下经验准则: 关于是否上传,有如下经验准则:
@ -39,7 +39,7 @@ version = "0.1.0"
regex = { git = "https://github.com/rust-lang/regex.git" } regex = { git = "https://github.com/rust-lang/regex.git" }
``` ```
可以看到,只有一个依赖,且该依赖的来源是 `Github` 上一个特定的仓库。由于我们没有指定任何版本信息,`Cargo` 会自动拉取该依赖库的最新版本( `master``main` 分支上的最新 `commit` )。 可以看到,只有一个依赖,且该依赖的来源是 `GitHub` 上一个特定的仓库。由于我们没有指定任何版本信息,`Cargo` 会自动拉取该依赖库的最新版本( `master``main` 分支上的最新 `commit` )。
这种使用方式,其实就错失了包管理工具的最大的优点:版本管理。例如你在今天构建使用了版本 `A`,然后过了一段时间后,由于依赖包的升级,新的构建却使用了大更新版本 `B`,结果因为版本不兼容,导致了构建失败。 这种使用方式,其实就错失了包管理工具的最大的优点:版本管理。例如你在今天构建使用了版本 `A`,然后过了一段时间后,由于依赖包的升级,新的构建却使用了大更新版本 `B`,结果因为版本不兼容,导致了构建失败。

@ -1,13 +1,13 @@
# 下载并构建 Package # 下载并构建 Package
如果看中 `Github` 上的某个开源 Rust 项目,那下载并构建它将是非常简单的。 如果看中 `GitHub` 上的某个开源 Rust 项目,那下载并构建它将是非常简单的。
```shell ```shell
$ git clone https://github.com/rust-lang/regex.git $ git clone https://github.com/rust-lang/regex.git
$ cd regex $ cd regex
``` ```
如上所示,直接从 `github` 上克隆下来想要的项目,然后使用 `cargo build` 进行构建即可: 如上所示,直接从 `GitHub` 上克隆下来想要的项目,然后使用 `cargo build` 进行构建即可:
```shell ```shell
$ cargo build $ cargo build

@ -27,9 +27,9 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
在有了持续集成后,只要编写好相应的编译、测试、发布配置文件,那持续集成平台会自动帮助我们完成整个相关的流程,期间无需任何人介入,高效且可靠。 在有了持续集成后,只要编写好相应的编译、测试、发布配置文件,那持续集成平台会自动帮助我们完成整个相关的流程,期间无需任何人介入,高效且可靠。
#### Github Actions #### GitHub Actions
关于如何使用 `Github Actions` 进行持续集成,在[之前的章节](https://course.rs/test/ci.html)已经有过详细的介绍,这里就不再赘述。 关于如何使用 `GitHub Actions` 进行持续集成,在[之前的章节](https://course.rs/test/ci.html)已经有过详细的介绍,这里就不再赘述。
#### Travis CI #### Travis CI

@ -32,7 +32,7 @@ fn main() {
> Note: [`package.build`](https://course.rs/cargo/reference/manifest.html#build) 可以用于改变构建脚本的名称,或者直接禁用该功能 > Note: [`package.build`](https://course.rs/cargo/reference/manifest.html#build) 可以用于改变构建脚本的名称,或者直接禁用该功能
#### 构建脚本的生命期 #### 构建脚本的生命
在项目被构建之前Cargo 会将构建脚本编译成一个可执行文件,然后运行该文件并执行相应的任务。 在项目被构建之前Cargo 会将构建脚本编译成一个可执行文件,然后运行该文件并执行相应的任务。
@ -40,7 +40,7 @@ fn main() {
需要注意的是Cargo 也不是每次都会重新编译构建脚本,只有当脚本的内容或依赖发生变化时才会。默认情况下,任何文件变化都会触发重新编译,如果你希望对其进行定制,可以使用 `rerun-if`命令,后文会讲。 需要注意的是Cargo 也不是每次都会重新编译构建脚本,只有当脚本的内容或依赖发生变化时才会。默认情况下,任何文件变化都会触发重新编译,如果你希望对其进行定制,可以使用 `rerun-if`命令,后文会讲。
在构建本成功执行后,我们的项目就会开始进行编译。如果构建脚本的运行过程中发生错误,脚本应该通过返回一个非 0 码来立刻退出,在这种情况下,构建脚本的输出会被打印到终端中。 在构建本成功执行后,我们的项目就会开始进行编译。如果构建脚本的运行过程中发生错误,脚本应该通过返回一个非 0 码来立刻退出,在这种情况下,构建脚本的输出会被打印到终端中。
#### 构建脚本的输入 #### 构建脚本的输入
@ -72,8 +72,8 @@ $ cargo run -vv
以下是 Cargo 能识别的通信指令以及简介,如果大家希望深入了解每个命令,可以点击具体的链接查看官方文档的说明。 以下是 Cargo 能识别的通信指令以及简介,如果大家希望深入了解每个命令,可以点击具体的链接查看官方文档的说明。
- [`cargo:rerun-if-changed=PATH`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rerun-if-changed) — 当指定路径的文件发生变化时Cargo 会重新运行脚本 - [`cargo:rerun-if-changed=PATH`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rerun-if-changed) — 当指定路径的文件发生变化时Cargo 会重新运行脚本
- [`cargo:rerun-if-env-changed=VAR`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rerun-if-env-changed) — 当指定的环境变量发生变化时Cargo 会重新运行脚本告诉 - [`cargo:rerun-if-env-changed=VAR`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rerun-if-env-changed) — 当指定的环境变量发生变化时Cargo 会重新运行脚本
- [`cargo:rustc-link-arg=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg) 将自定义的 flags 传给 linker用于后续的基准性能测试 benchmark、 可执行文件 binary,、`cdylib` 包、示例 和测试 - [`cargo:rustc-link-arg=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg) 将自定义的 flags 传给 linker用于后续的基准性能测试 benchmark、 可执行文件 binary,、`cdylib` 包、示例和测试
- [`cargo:rustc-link-arg-bin=BIN=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg-bin) 自定义的 flags 传给 linker用于可执行文件 `BIN` - [`cargo:rustc-link-arg-bin=BIN=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg-bin) 自定义的 flags 传给 linker用于可执行文件 `BIN`
- [`cargo:rustc-link-arg-bins=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg-bins) 自定义的 flags 传给 linker用于可执行文件 - [`cargo:rustc-link-arg-bins=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg-bins) 自定义的 flags 传给 linker用于可执行文件
- [`cargo:rustc-link-arg-tests=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg-tests) 自定义的 flags 传给 linker用于测试 - [`cargo:rustc-link-arg-tests=FLAG`](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#rustc-link-arg-tests) 自定义的 flags 传给 linker用于测试
@ -90,7 +90,7 @@ $ cargo run -vv
## 构建脚本的依赖 ## 构建脚本的依赖
构建脚本也可以引入其它基于 Cargo 的依赖包,只需要修改`Cargo.toml` 中添加以下内容: 构建脚本也可以引入其它基于 Cargo 的依赖包,只需要在 `Cargo.toml` 中添加或修改以下内容:
```toml ```toml
[build-dependencies] [build-dependencies]
@ -115,7 +115,7 @@ links = "foo"
Cargo 要求一个本地库最多只能被一个项目所链接,换而言之,你无法让两个项目链接到同一个本地库,但是有一种方法可以降低这种限制,感兴趣的同学可以看看[官方文档](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#-sys-packages)。 Cargo 要求一个本地库最多只能被一个项目所链接,换而言之,你无法让两个项目链接到同一个本地库,但是有一种方法可以降低这种限制,感兴趣的同学可以看看[官方文档](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#-sys-packages)。
假设 A 项目的构建脚本生成任意数量的 kv 形式的元数据,那这些元数据传递给 A 用作依赖包的项目的构建脚本。例如,如果包 `bar` 依赖于 `foo`,当 `foo` 生成 `key==value` 形式的构建脚本元数据时,那么 `bar` 的构建脚本就可以通过环境变量的形式使用该元数据:`DEP_FOO_KEY=value`。 假设 A 项目的构建脚本生成任意数量的 kv 形式的元数据,那这些元数据传递给 A 用作依赖包的项目的构建脚本。例如,如果包 `bar` 依赖于 `foo`,当 `foo` 生成 `key=value` 形式的构建脚本元数据时,那么 `bar` 的构建脚本就可以通过环境变量的形式使用该元数据:`DEP_FOO_KEY=value`。
需要注意的是,该元数据只能传给直接相关者,对于间接的,例如依赖的依赖,就无能为力了。 需要注意的是,该元数据只能传给直接相关者,对于间接的,例如依赖的依赖,就无能为力了。

@ -108,7 +108,7 @@ uuid = { git = 'https://github.com/uuid-rs/uuid' }
#### 间接使用 `patch` #### 间接使用 `patch`
现在假设项目 `A` 的依赖是 `B``uuid`,而 `B` 的依赖也是 `uuid`,此时我们可以让 `A``B` 都使用来自 `github` 的 `patch` 版本,配置如下: 现在假设项目 `A` 的依赖是 `B``uuid`,而 `B` 的依赖也是 `uuid`,此时我们可以让 `A``B` 都使用来自 `GitHub` 的 `patch` 版本,配置如下:
```toml ```toml
[package] [package]

@ -184,7 +184,7 @@ homepage = "https://serde.rs/"
#### repository #### repository
设置项目的源代码仓库地址,例如 `github` 链接: 设置项目的源代码仓库地址,例如 `GitHub` 链接:
```toml ```toml
[package] [package]

@ -25,7 +25,7 @@ overflow-checks = false # 关闭整数溢出检查
需要注意的是,每一种 profile 都可以单独的进行设置,例如上面的 `[profile.dev]` 需要注意的是,每一种 profile 都可以单独的进行设置,例如上面的 `[profile.dev]`
如果是工作空间的话,只有根 package 的 `Cargo.toml` 中的 `[profile` 设置才会被使用,其它成员或依赖包中的设置会被自动忽略。 如果是工作空间的话,只有根 package 的 `Cargo.toml` 中的 `[profile]` 设置才会被使用,其它成员或依赖包中的设置会被自动忽略。
另外profile 还能在 Cargo 自身的配置文件中进行覆盖,总之,通过 `.cargo/config.toml` 或环境变量的方式所指定的 `profile` 配置会覆盖项目的 `Cargo.toml` 中相应的配置。 另外profile 还能在 Cargo 自身的配置文件中进行覆盖,总之,通过 `.cargo/config.toml` 或环境变量的方式所指定的 `profile` 配置会覆盖项目的 `Cargo.toml` 中相应的配置。
@ -126,9 +126,9 @@ cargo build --profile release-lto
支持的选项包括: 支持的选项包括:
- `false`: 只会对代码生成单元中的本地包进行 `thin LTO` 优化,若代码生成单元数为 1 或者 `opt-level` 为 0则不会进行任何 LTO 优化 - `false`: 只会对代码生成单元中的本地包进行 `"thin" LTO` 优化,若代码生成单元数为 1 或者 `opt-level` 为 0则不会进行任何 LTO 优化
- `true``fat`:对依赖图中的所有包进行 `fat LTO` 优化 - `true``"fat"`:对依赖图中的所有包进行 `"fat" LTO` 优化
- `thin`:对依赖图的所有包进行 [`thin LTO`](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html),相比 `fat` 来说,它仅牺牲了一点性能,但是换来了链接时间的可观减少 - `"thin"`:对依赖图的所有包进行 [`"thin" LTO`](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html),相比 `"fat"` 来说,它仅牺牲了一点性能,但是换来了链接时间的可观减少
- `off` 禁用 LTO - `off` 禁用 LTO
如果大家想了解跨语言 LTO可以看下 [-C linker-plugin-lto](https://doc.rust-lang.org/stable/rustc/codegen-options/index.html#linker-plugin-lto) 标志。 如果大家想了解跨语言 LTO可以看下 [-C linker-plugin-lto](https://doc.rust-lang.org/stable/rustc/codegen-options/index.html#linker-plugin-lto) 标志。

@ -1,12 +1,12 @@
# 发布到 crates.io # 发布到 crates.io
如果你想要把自己的开源项目分享给全世界,那最好的办法自然是 github。但如果是 Rust 的库,那除了发布到 github 外,我们还可以将其发布到 [crates.io](https://crates.io) 上,然后其它用户就可以很简单的对其进行引用。 如果你想要把自己的开源项目分享给全世界,那最好的办法自然是 GitHub。但如果是 Rust 的库,那除了发布到 GitHub 外,我们还可以将其发布到 [crates.io](https://crates.io) 上,然后其它用户就可以很简单的对其进行引用。
> 注意:发布包到 `crates.io` 后,特定的版本无法被覆盖,要发布就必须使用新的版本号,代码也无法被删除! > 注意:发布包到 `crates.io` 后,特定的版本无法被覆盖,要发布就必须使用新的版本号,代码也无法被删除!
## 首次发布之前 ## 首次发布之前
**首先,我们需要一个账号**:访问 crates.io 的[主页](https://crates.io),然后在右上角使用 Github 账户登陆,接着访问你的[账户设置](https://crates.io/settings/profile)页面,进入到 API Tokens 标签页下,生成新的 Token并使用该 Token 在终端中进行登录: **首先,我们需要一个账号**:访问 crates.io 的[主页](https://crates.io),然后在右上角使用 GitHub 账户登陆,接着访问你的[账户设置](https://crates.io/settings/profile)页面,进入到 API Tokens 标签页下,生成新的 Token并使用该 Token 在终端中进行登录:
```shell ```shell
$ cargo login abcdefghijklmnopqrstuvwxyz012345 $ cargo login abcdefghijklmnopqrstuvwxyz012345
@ -52,7 +52,7 @@ $ cargo publish --dry-run
你可以在 `target/package` 目录下观察生成的 `.crate` 文件。例如,目前 `crates.io` 要求该文件的大小不能超过 10MB你可以通过手动检查该文件的大小来确保不会无意间打包进一些较大的资源文件比如测试数据、网站文档或生成的代码等。我们还可以使用以下命令来检查其中包含的文件: 你可以在 `target/package` 目录下观察生成的 `.crate` 文件。例如,目前 `crates.io` 要求该文件的大小不能超过 10MB你可以通过手动检查该文件的大小来确保不会无意间打包进一些较大的资源文件比如测试数据、网站文档或生成的代码等。我们还可以使用以下命令来检查其中包含的文件:
```shell ```shell
$cargo package --list $ cargo package --list
``` ```
当打包时Cargo 会自动根据版本控制系统的配置来忽略指定的文件,例如 `.gitignore`。除此之外,你还可以通过 [`exclude`](https://course.rs/cargo/reference/manifest.html#exclude和include) 来排除指定的文件: 当打包时Cargo 会自动根据版本控制系统的配置来忽略指定的文件,例如 `.gitignore`。除此之外,你还可以通过 [`exclude`](https://course.rs/cargo/reference/manifest.html#exclude和include) 来排除指定的文件:
@ -123,12 +123,12 @@ $ cargo owner --add github:rust-lang:owners
$ cargo owner --remove github:rust-lang:owners $ cargo owner --remove github:rust-lang:owners
``` ```
命令中使用的 ownerID 必须是 Github 用户名或 Team 名。 命令中使用的 ownerID 必须是 GitHub 用户名或 Team 名。
一旦一个用户 `B` 通过 `--add` 被加入到 `owner` 列表中他将拥有该包相关的所有权利。例如发布新版本、yank 一个版本,还能增加和移除 owner包含添加 `B` 为 owner 的 `A` 都可以被移除! 一旦一个用户 `B` 通过 `--add` 被加入到 `owner` 列表中他将拥有该包相关的所有权利。例如发布新版本、yank 一个版本,还能增加和移除 owner包含添加 `B` 为 owner 的 `A` 都可以被移除!
因此,我们必须严肃的指出:**不要将你不信任的人添加为 owner !** 免得哪天反目成仇后,他把你移除了 - , - 因此,我们必须严肃的指出:**不要将你不信任的人添加为 owner !** 免得哪天反目成仇后,他把你移除了 - , -
但是对于 Team 又有所不同,通过 `-add` 添加的 Github Team owner只拥有受限的权利。它们可以发布或 yank 某个版本,但是他们**不能添加或移除** owner总之Team 除了可以很方便的管理所有者分组的同时,还能防止一些未知的恶意。 但是对于 Team 又有所不同,通过 `-add` 添加的 GitHub Team owner只拥有受限的权利。它们可以发布或 yank 某个版本,但是他们**不能添加或移除** owner总之Team 除了可以很方便的管理所有者分组的同时,还能防止一些未知的恶意。
如果大家在添加 team 时遇到问题,可以看看官方的[相关文档](https://doc.rust-lang.org/stable/cargo/reference/publishing.html#github-permissions),由于绝大多数人都无需此功能,因此这里不再详细展开。 如果大家在添加 team 时遇到问题,可以看看官方的[相关文档](https://doc.rust-lang.org/stable/cargo/reference/publishing.html#github-permissions),由于绝大多数人都无需此功能,因此这里不再详细展开。

@ -1,6 +1,6 @@
# 指定依赖项 # 指定依赖项
我们的项目可以引用在 `crates.io``github` 上的依赖包,也可以引用存放在本地文件系统中的依赖包。 我们的项目可以引用在 `crates.io``GitHub` 上的依赖包,也可以引用存放在本地文件系统中的依赖包。
大家可能会想,直接从前两个引用即可,为何还提供了本地方式?可以设想下,如果你要有一个正处于开发中的包,然后需要在本地的另一个项目中引用测试,那是将该包先传到网上,然后再引用简单,还是直接从本地路径的方式引用简单呢?答案显然不言而喻。 大家可能会想,直接从前两个引用即可,为何还提供了本地方式?可以设想下,如果你要有一个正处于开发中的包,然后需要在本地的另一个项目中引用测试,那是将该包先传到网上,然后再引用简单,还是直接从本地路径的方式引用简单呢?答案显然不言而喻。
@ -83,7 +83,7 @@ time = "0.1.12"
>= 1.2, < 1.5 >= 1.2, < 1.5
``` ```
需要注意,以上的版本号规则仅仅针对 `crate.io` 和基于它搭建的注册服务(例如科大服务源) ,其它注册服务(例如 github )有自己相应的规则。 需要注意,以上的版本号规则仅仅针对 `crate.io` 和基于它搭建的注册服务(例如科大服务源) ,其它注册服务(例如 GitHub )有自己相应的规则。
## 从其它注册服务引入依赖包 ## 从其它注册服务引入依赖包

@ -4,7 +4,7 @@
## 多国语言的"世界,你好" ## 多国语言的"世界,你好"
还记得大明湖畔等你的 [VSCode IDE](https://course.rs/first-try/editor.md) 和通过 `Cargo` 创建的 [世界,你好](https://course.rs/first-try/cargo.html) 工程吗? 还记得大明湖畔等你的 [VSCode IDE](https://course.rs/first-try/editor.html) 和通过 `Cargo` 创建的 [世界,你好](https://course.rs/first-try/cargo.html) 工程吗?
现在使用 VSCode 打开 [上一节](https://course.rs/first-try/cargo.html) 中创建的 `world_hello` 工程,然后进入 `main.rs` 文件。(此文件是当前 Rust 工程的入口文件,和其它语言几无区别。) 现在使用 VSCode 打开 [上一节](https://course.rs/first-try/cargo.html) 中创建的 `world_hello` 工程,然后进入 `main.rs` 文件。(此文件是当前 Rust 工程的入口文件,和其它语言几无区别。)

@ -1 +1 @@
# Github # GitHub

@ -26,6 +26,7 @@
| [&] | 引用 | 常规引用是一个指针类型,指向了对象存储的内存地址 | | [&] | 引用 | 常规引用是一个指针类型,指向了对象存储的内存地址 |
| [\*] | 解引用 | 解出引用所指向的值 | | [\*] | 解引用 | 解出引用所指向的值 |
| [@] | 变量绑定 | 为一个字段绑定另外一个变量 | | [@] | 变量绑定 | 为一个字段绑定另外一个变量 |
| `_` | | 忽略该值或者类型 |
| ['a: 'b] | 生命周期约束 | 用来说明两个生命周期的长短 | | ['a: 'b] | 生命周期约束 | 用来说明两个生命周期的长短 |
| [{:?}] {:#?} | 打印结构体信息 | 使用 `#[derive(Debug)]` 派生实现 `Debug` 特征 | | [{:?}] {:#?} | 打印结构体信息 | 使用 `#[derive(Debug)]` 派生实现 `Debug` 特征 |
| A | | AIntroduction | | A | | AIntroduction |
@ -44,10 +45,14 @@
## A ## A
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| ---- | ------ | ------------- | | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| [] | | | | [array 数组] | 数组 | 长度固定<br>元素必须有相同的类型<br>依次线性排列<br>可以通过索引访问其中的元素<br>`let a: [i32; 5] = [1, 2, 3, 4, 5];` |
| A | KWA | AIntroduction | | [array slice] | 数组切片 | `let slice: &[i32] = &a[1..3];` |
| A | KWA | AIntroduction |
[array 数组]: https://course.rs/basic/compound-type/array.html
[array slice]: https://course.rs/basic/compound-type/array.html#数组切片
[back](#head) [back](#head)
@ -59,12 +64,14 @@
| [变量作用域] | 所有权 | 作用域是一个变量在程序中有效的范围 | | [变量作用域] | 所有权 | 作用域是一个变量在程序中有效的范围 |
| [表达式] | | 进行求值,结尾无 `;`,有返回值 | | [表达式] | | 进行求值,结尾无 `;`,有返回值 |
| [bool 布尔] | 布尔类型 | `true` `false`,占用 1 字节 | | [bool 布尔] | 布尔类型 | `true` `false`,占用 1 字节 |
| [break] | 循环控制 | 直接跳出当前整个循环 |
| B | KWB | BIntroduction | | B | KWB | BIntroduction |
[变量遮蔽]: https://course.rs/basic/variable.html#变量遮蔽shadowing [变量遮蔽]: https://course.rs/basic/variable.html#变量遮蔽shadowing
[变量作用域]: https://course.rs/basic/ownership/ownership.html#变量作用域 [变量作用域]: https://course.rs/basic/ownership/ownership.html#变量作用域
[bool 布尔]: https://course.rs/basic/base-type/char-bool.html#布尔bool [bool 布尔]: https://course.rs/basic/base-type/char-bool.html#布尔bool
[表达式]: https://course.rs/basic/base-type/statement-expression.html#表达式 [表达式]: https://course.rs/basic/base-type/statement-expression.html#表达式
[break]: https://course.rs/basic/flow-control.html#break
[back](#head) [back](#head)
@ -75,6 +82,7 @@
| [char 字符] | 字符类型 | 使用 `''` 表示,所有的 Unicode 值 | | [char 字符] | 字符类型 | 使用 `''` 表示,所有的 Unicode 值 |
| [const 常量] | constant | `const MAX_POINTS: u32 = 100_000;` | | [const 常量] | constant | `const MAX_POINTS: u32 = 100_000;` |
| [Copy 拷贝] | 浅拷贝 | 任何基本类型的组合可以 `Copy`,不需要分配内存或某种形式资源的类型是可以 `Copy` 的。 | | [Copy 拷贝] | 浅拷贝 | 任何基本类型的组合可以 `Copy`,不需要分配内存或某种形式资源的类型是可以 `Copy` 的。 |
| [continue] | 循环控制 | 跳过当前当次的循环,开始下次的循环 |
| [Clone 克隆] | 深拷贝 | 需要复制堆上的数据时,可以使用 `.clone()` 方法 | | [Clone 克隆] | 深拷贝 | 需要复制堆上的数据时,可以使用 `.clone()` 方法 |
| C | KWC | CIntroduction | | C | KWC | CIntroduction |
@ -82,6 +90,7 @@
[const 常量]: https://course.rs/basic/variable.html#变量和常量之间的差异 [const 常量]: https://course.rs/basic/variable.html#变量和常量之间的差异
[copy 拷贝]: https://course.rs/basic/ownership/ownership.html#拷贝浅拷贝 [copy 拷贝]: https://course.rs/basic/ownership/ownership.html#拷贝浅拷贝
[clone 克隆]: https://course.rs/basic/ownership/ownership.html#克隆深拷贝 [clone 克隆]: https://course.rs/basic/ownership/ownership.html#克隆深拷贝
[continue]: https://course.rs/basic/flow-control.html#continue
[back](#head) [back](#head)
@ -106,12 +115,14 @@
## F ## F
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| -------- | -------- | ------------------------ | | ---------- | -------- | ---------------------------- |
| [浮点数] | 数值类型 | `f32`<br>`f64`(默认类型) | | [浮点数] | 数值类型 | `f32`<br>`f64`(默认类型) |
| F | KWF | FIntroduction | | [for 循环] | 循环控制 | `for item in &collection {}` |
| F | KWF | FIntroduction |
[浮点数]: https://course.rs/basic/base-type/numbers.html#浮点类型 [浮点数]: https://course.rs/basic/base-type/numbers.html#浮点类型
[for 循环]: https://course.rs/basic/flow-control.html#for-循环
[back](#head) [back](#head)
@ -136,9 +147,14 @@
## I ## I
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| ---- | ------ | ------------- | | --------- | -------- | -------------------------- |
| I | KWI | IIntroduction | | [if else] | 流程控制 | 根据条件执行不同的代码分支 |
| [else if] | 流程控制 | 处理多重条件 |
| I | KWI | IIntroduction |
[if else]: https://course.rs/basic/flow-control.html#使用-if-来做分支控制
[else if]: https://course.rs/basic/flow-control.html#使用-else-if-来处理多重条件
[back](#head) [back](#head)
@ -160,14 +176,17 @@
## L ## L
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| --------- | -------- | ----------------------------- | | ----------- | -------- | ------------------------------ |
| [let] | 变量绑定 | `let x : u32 = 5;` | | [let] | 变量绑定 | `let x : u32 = 5;` |
| [let mut] | 可变变量 | `let mut x : u32 = 5; x = 9;` | | [let mut] | 可变变量 | `let mut x : u32 = 5; x = 9;` |
| L | KWL | LIntroduction | | [loop 循环] | 循环控制 | 无限循环,注意要配合 [`break`] |
| L | KWL | LIntroduction |
[let]: https://course.rs/basic/variable.html#变量绑定 [let]: https://course.rs/basic/variable.html#变量绑定
[let mut]: https://course.rs/basic/variable.html#变量可变性 [let mut]: https://course.rs/basic/variable.html#变量可变性
[`break`]: https://course.rs/basic/flow-control.html#break
[loop 循环]: https://course.rs/basic/flow-control.html#loop-循环
[back](#head) [back](#head)
@ -283,9 +302,12 @@
## W ## W
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| ---- | ------ | ------------- | | ------------ | -------- | ------------------------------------------------------ |
| W | KWW | WIntroduction | | [while 循环] | 循环控制 | 当条件为 `true` 时,继续循环,条件为 `false`,跳出循环 |
| W | KWW | WIntroduction |
[while 循环]: https://course.rs/basic/flow-control.html#while-循环
[back](#head) [back](#head)

@ -130,7 +130,7 @@ Rust 语言表达能力更强,性能更高。同时线程安全方面 Rust 也
- Google 除了在安卓系统的部分模块中使用 Rust 外,还在它最新的操作系统 Fuchsia 中重度使用 Rust - Google 除了在安卓系统的部分模块中使用 Rust 外,还在它最新的操作系统 Fuchsia 中重度使用 Rust
- Facebook 使用 Rust 来增强自己的网页端、移动端和 API 服务的性能,同时还写了 Hack 编程语言的虚拟机 - Facebook 使用 Rust 来增强自己的网页端、移动端和 API 服务的性能,同时还写了 Hack 编程语言的虚拟机
- Microsoft 使用 Rust 为 Azure 平台提供一些组件,其中包括 IoT 的核心服务 - Microsoft 使用 Rust 为 Azure 平台提供一些组件,其中包括 IoT 的核心服务
- Github 和 npmjs.com使用 Rust 提供高达每天 13 亿次的 npm 包下载 - GitHub 和 npmjs.com使用 Rust 提供高达每天 13 亿次的 npm 包下载
- Rust 目前已经成为全世界区块链平台的首选开发语言 - Rust 目前已经成为全世界区块链平台的首选开发语言
- TiDB国内最有名的开源分布式数据库 - TiDB国内最有名的开源分布式数据库

@ -1,6 +1,6 @@
# 用 Github Actions 进行持续集成 # 用 GitHub Actions 进行持续集成
[Github Actions](https://github.com/features/actions) 是官方于 2018 年推出的持续集成服务,它非常强大,本文将手把手带领大家学习如何使用 `Github Actions` 对 Rust 项目进行持续集成。 [GitHub Actions](https://github.com/features/actions) 是官方于 2018 年推出的持续集成服务,它非常强大,本文将手把手带领大家学习如何使用 `GitHub Actions` 对 Rust 项目进行持续集成。
持续集成是软件开发中异常重要的一环,大家应该都听说过 `Jenkins`,它就是一个拥有悠久历史的持续集成工具。简单来说,持续集成会定期拉取同一个项目中所有成员的相关代码,对其进行自动化构建。 持续集成是软件开发中异常重要的一环,大家应该都听说过 `Jenkins`,它就是一个拥有悠久历史的持续集成工具。简单来说,持续集成会定期拉取同一个项目中所有成员的相关代码,对其进行自动化构建。
@ -8,11 +8,11 @@
在有了持续集成后,只要编写好相应的编译、测试、发布配置文件,那持续集成平台会自动帮助我们完成整个相关的流程,期间无需任何人介入,高效且可靠。 在有了持续集成后,只要编写好相应的编译、测试、发布配置文件,那持续集成平台会自动帮助我们完成整个相关的流程,期间无需任何人介入,高效且可靠。
## Github Actions ## GitHub Actions
而本文的主角正是这样的持续集成平台,它由 Github 官方提供,并且跟 github 进行了深度的整合,其中 `actions` 代表了代码拉取、测试运行、登陆远程服务器、发布到第三方服务等操作行为。 而本文的主角正是这样的持续集成平台,它由 GitHub 官方提供,并且跟 GitHub 进行了深度的整合,其中 `actions` 代表了代码拉取、测试运行、登陆远程服务器、发布到第三方服务等操作行为。
最妙的是 Github 发现这些 `actions` 其实在很多项目中都是类似的,意味着 `actions` 完全可以被多个项目共享使用,而不是每个项目都从零开发自己的 `actions` 最妙的是 GitHub 发现这些 `actions` 其实在很多项目中都是类似的,意味着 `actions` 完全可以被多个项目共享使用,而不是每个项目都从零开发自己的 `actions`
若你需要某个 `action`,不必自己写复杂的脚本,直接引用他人写好的 `action` 即可,整个持续集成过程,就变成了多个 `action` 的组合,这就是` GitHub Actions` 最厉害的地方。 若你需要某个 `action`,不必自己写复杂的脚本,直接引用他人写好的 `action` 即可,整个持续集成过程,就变成了多个 `action` 的组合,这就是` GitHub Actions` 最厉害的地方。
@ -20,8 +20,8 @@
既然 `action` 这么强大,我们就可以将自己的 `action` 分享给他人,也可以引用他人分享的 `action`,有以下几种方式: 既然 `action` 这么强大,我们就可以将自己的 `action` 分享给他人,也可以引用他人分享的 `action`,有以下几种方式:
1. 将你的 `action` 放在 github 上的公共仓库中,这样其它开发者就可以引用,例如 [github-profile-summary-cards](https://github.com/vn7n24fzkq/github-profile-summary-cards) 就提供了相应的 `action`,可以生成 github 用户统计信息,然后嵌入到你的个人主页中,具体效果[见这里](https://github.com/sunface) 1. 将你的 `action` 放在 GitHub 上的公共仓库中,这样其它开发者就可以引用,例如 [github-profile-summary-cards](https://github.com/vn7n24fzkq/github-profile-summary-cards) 就提供了相应的 `action`,可以生成 GitHub 用户统计信息,然后嵌入到你的个人主页中,具体效果[见这里](https://github.com/sunface)
2. Github 提供了一个[官方市场](https://github.com/marketplace?type=actions),里面收集了许多质量不错的 `actions`,并支持在线搜索 2. GitHub 提供了一个[官方市场](https://github.com/marketplace?type=actions),里面收集了许多质量不错的 `actions`,并支持在线搜索
3. [awesome-actions](https://github.com/sdras/awesome-actions),由三方开发者收集并整理的 actions 3. [awesome-actions](https://github.com/sdras/awesome-actions),由三方开发者收集并整理的 actions
4. [starter workflows](https://github.com/actions/starter-workflows),由官方提供的工作流( workflow )模版 4. [starter workflows](https://github.com/actions/starter-workflows),由官方提供的工作流( workflow )模版
@ -39,18 +39,18 @@ actions/setup-node@f099707 # 指向一个 commit
## Actions 基础 ## Actions 基础
在了解了何为 Github Actions 后,再来通过一个基本的例子来学习下它的基本概念,注意,由于篇幅有限,我们只会讲解最常用的部分,如果想要完整的学习,请移步[这里](https://docs.github.com/en/actions)。 在了解了何为 GitHub Actions 后,再来通过一个基本的例子来学习下它的基本概念,注意,由于篇幅有限,我们只会讲解最常用的部分,如果想要完整的学习,请移步[这里](https://docs.github.com/en/actions)。
#### 创建 action demo #### 创建 action demo
首先,为了演示,我们需要创建一个公开的 github 仓库 `rust-action`,然后在仓库主页的导航栏中点击 `Actions` ,你会看到如下页面 : 首先,为了演示,我们需要创建一个公开的 GitHub 仓库 `rust-action`,然后在仓库主页的导航栏中点击 `Actions` ,你会看到如下页面 :
<img src="https://pic1.zhimg.com/80/v2-4bb58f042c7a285219910bfd3c259464_1440w.jpg" /> <img src="https://pic1.zhimg.com/80/v2-4bb58f042c7a285219910bfd3c259464_1440w.jpg" />
接着点击 `set up a workflow yourself ->` ,你将看到系统为你自动创建的一个工作流 workflow ,在 `rust-action/.github/workflows/main.yml` 文件中包含以下内容: 接着点击 `set up a workflow yourself ->` ,你将看到系统为你自动创建的一个工作流 workflow ,在 `rust-action/.github/workflows/main.yml` 文件中包含以下内容:
```yml ```yml
# 下面是一个基础的工作流,你可以基于它来编写自己的 Github Actions # 下面是一个基础的工作流,你可以基于它来编写自己的 GitHub Actions
name: CI name: CI
# 控制工作流何时运行 # 控制工作流何时运行
@ -113,23 +113,23 @@ jobs:
<img src="https://pic1.zhimg.com/80/v2-94b46f23b5d63de35eae7f0425bb99b7_1440w.jpg" /> <img src="https://pic1.zhimg.com/80/v2-94b46f23b5d63de35eae7f0425bb99b7_1440w.jpg" />
至此,我们已经初步掌握 `Github Actions` 的用法,现在来看看一些基本的概念。 至此,我们已经初步掌握 `GitHub Actions` 的用法,现在来看看一些基本的概念。
#### 基本概念 #### 基本概念
- **Github Actions**,每个项目都拥有一个 `Actions` ,可以包含多个工作流 - **GitHub Actions**,每个项目都拥有一个 `Actions` ,可以包含多个工作流
- **workflow 工作流**,描述了一次持续集成的过程 - **workflow 工作流**,描述了一次持续集成的过程
- **job 作业**,一个工作流可以包含多个作业,因为一次持续集成本身就由多个不同的部分组成 - **job 作业**,一个工作流可以包含多个作业,因为一次持续集成本身就由多个不同的部分组成
- **step 步骤**,每个作业由多个步骤组成,按照顺序一步一步完成 - **step 步骤**,每个作业由多个步骤组成,按照顺序一步一步完成
- **action 动作**,每个步骤可以包含多个动作,例如上例中的 `Run a multi-line script` 步骤就包含了两个动作 - **action 动作**,每个步骤可以包含多个动作,例如上例中的 `Run a multi-line script` 步骤就包含了两个动作
可以看出,每一个概念都是相互包含的关系,前者包含了后者,层层相扣,正因为这些精心设计的对象才有了强大的 `Github Actions`。 可以看出,每一个概念都是相互包含的关系,前者包含了后者,层层相扣,正因为这些精心设计的对象才有了强大的 `GitHub Actions`。
#### on #### on
`on` 可以设定事件用于触发工作流的运行: `on` 可以设定事件用于触发工作流的运行:
1. 一个或多个 Github 事件,例如 `push` 一个 `commit`、创建一个 `issue`、提交一次 `pr` 等等,详细的事件列表参见[这里](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows) 1. 一个或多个 GitHub 事件,例如 `push` 一个 `commit`、创建一个 `issue`、提交一次 `pr` 等等,详细的事件列表参见[这里](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows)
2. 预定的时间,例如每天零点零分触发,详情见[这里](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule) 2. 预定的时间,例如每天零点零分触发,详情见[这里](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule)
@ -138,7 +138,7 @@ on:
schedule: -cron:'0 0 * * *' schedule: -cron:'0 0 * * *'
``` ```
3. 外部事件触发,例如你可以通过 `REST API` 向 Github 发送请求去触发,具体请查阅[官方文档](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#repository_dispatch) 3. 外部事件触发,例如你可以通过 `REST API` 向 GitHub 发送请求去触发,具体请查阅[官方文档](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#repository_dispatch)
#### jobs #### jobs
@ -159,9 +159,9 @@ jobs:
#### runs-on #### runs-on
指定作业的运行环境,运行器 `runner` 分为两种:`GitHub-hosted runner` 和 `self-hosted runner`,后者是使用自己的机器来运行作业,但是需要 Github 能进行访问并给予相应的机器权限,感兴趣的同学可以看看[这里](https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job#choosing-self-hosted-runners)。 指定作业的运行环境,运行器 `runner` 分为两种:`GitHub-hosted runner` 和 `self-hosted runner`,后者是使用自己的机器来运行作业,但是需要 GitHub 能进行访问并给予相应的机器权限,感兴趣的同学可以看看[这里](https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job#choosing-self-hosted-runners)。
而对于前者Github 提供了以下的运行环境: 而对于前者GitHub 提供了以下的运行环境:
<img src="https://pic2.zhimg.com/80/v2-614999565cc513715aaf156c2e478991_1440w.jpg" /> <img src="https://pic2.zhimg.com/80/v2-614999565cc513715aaf156c2e478991_1440w.jpg" />
@ -221,18 +221,18 @@ jobs:
如果有多个 `env` 存在,会使用就近那个。 如果有多个 `env` 存在,会使用就近那个。
至此,`Github Actions` 的常用内容大家已经基本了解,下面来看一个实用的示例。 至此,`GitHub Actions` 的常用内容大家已经基本了解,下面来看一个实用的示例。
## 真实示例:生成 Github 统计卡片 ## 真实示例:生成 GitHub 统计卡片
相信大家看过不少用户都定制了自己的个性化 Github 首页,这个是通过在个人名下创建一个同名的仓库来实现的,该仓库中的 `Readme.md` 的内容会自动展示在你的个人首页中,例如 `Sunface` 的[个人首页](https://github.com/sunface) 和内容所在的[仓库](https://github.com/sunface/sunface)。 相信大家看过不少用户都定制了自己的个性化 GitHub 首页,这个是通过在个人名下创建一个同名的仓库来实现的,该仓库中的 `Readme.md` 的内容会自动展示在你的个人首页中,例如 `Sunface` 的[个人首页](https://github.com/sunface) 和内容所在的[仓库](https://github.com/sunface/sunface)。
大家可能会好奇上面链接中的 Github 统计卡片如何生成,其实有两种办法: 大家可能会好奇上面链接中的 GitHub 统计卡片如何生成,其实有两种办法:
- 使用 [github-readme-stats](https://github.com/anuraghazra/github-readme-stats) - 使用 [github-readme-stats](https://github.com/anuraghazra/github-readme-stats)
- 使用 `Github Actions` 来引用其它人提供的 `action` 生成对应的卡片,再嵌入进来, `Sunface` 的个人首页就是这么做的 - 使用 `GitHub Actions` 来引用其它人提供的 `action` 生成对应的卡片,再嵌入进来, `Sunface` 的个人首页就是这么做的
第一种的优点就是非常简单,缺点是样式不太容易统一,不能对齐对于强迫症来说实在难受 :( 而后者的优点是规规整整的卡片,缺点就是使用起来更加复杂,而我们正好借此来看看真实的 `Github Actions` 长什么样。 第一种的优点就是非常简单,缺点是样式不太容易统一,不能对齐对于强迫症来说实在难受 :( 而后者的优点是规规整整的卡片,缺点就是使用起来更加复杂,而我们正好借此来看看真实的 `GitHub Actions` 长什么样。
首先,在你的同名项目下创建 `.github/workflows/profile-summary-cards.yml` 文件,然后填入以下内容: 首先,在你的同名项目下创建 `.github/workflows/profile-summary-cards.yml` 文件,然后填入以下内容:

@ -198,4 +198,4 @@ Rust 提供了单元测试和集成测试两种方式来帮助我们组织测试
- 单元测试的模块和待测试的代码在同一个文件中,且可以很方便地对私有函数进行测试 - 单元测试的模块和待测试的代码在同一个文件中,且可以很方便地对私有函数进行测试
- 集成测试文件放在项目根目录下的 `tests` 目录中,由于该目录下每个文件都是一个包,我们必须要引入待测试的代码到当前包的作用域中,才能进行测试,正因为此,集成测试只能对声明为 `pub` 的 API 进行测试 - 集成测试文件放在项目根目录下的 `tests` 目录中,由于该目录下每个文件都是一个包,我们必须要引入待测试的代码到当前包的作用域中,才能进行测试,正因为此,集成测试只能对声明为 `pub` 的 API 进行测试
下个章节,我们再来看看该如何使用 `Github Actions` 对 Rust 项目进行持续集成。 下个章节,我们再来看看该如何使用 `GitHub Actions` 对 Rust 项目进行持续集成。

@ -93,3 +93,8 @@ table {
content: "繁星点点尽在你的指尖 🌟"; content: "繁星点点尽在你的指尖 🌟";
margin-left: 4px; margin-left: 4px;
} }
/* Fix on mobile device */
code {
word-break: break-word;
}

@ -22,7 +22,7 @@
## 2022-03-28 ## 2022-03-28
- 新增章节:[双单向链表](https://course.rs/too-many-lists/advanced-lists/double-singly.html) - 新增章节:[双单向链表](https://course.rs/too-many-lists/advanced-lists/double-singly.html)
- 优化样式:增加目录中的区域性标题、修改 github 图标和说明,通过 js 增加访问者统计 - 优化样式:增加目录中的区域性标题、修改 GitHub 图标和说明,通过 js 增加访问者统计
- 新增创作感悟 - 新增创作感悟
## 2022-03-27 ## 2022-03-27

Loading…
Cancel
Save