Merge pull request #928 from zongzi531/hotfix/deque

fix: typo shell symbol in cargo script and etc
pull/934/head
Sunface 2 years ago committed by GitHub
commit e9f435d083
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -432,6 +432,7 @@ fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
```shell
$ cargo run
Running `target/debug/hello_macro`
Hello, Macro! My name is Sunfei!
Hello, Macro! My name is Sunface!

@ -11,7 +11,7 @@ $ rustup update stable
## 基于源码的代码覆盖
rustc 新增了基于 LLVM 的代码覆盖率测量,想要测试的同学可以通过以下方式重新构建你的项目:
```shell
RUSTFLAGS="-C instrument-coverage" cargo build
$ RUSTFLAGS="-C instrument-coverage" cargo build
```
运行新生成的可执行文件将在当前目录下产生一个 `default.profraw` 文件( 路径和文件名可以通过环境变量进行[覆盖](https://doc.rust-lang.org/stable/rustc/instrument-coverage.html#running-the-instrumented-binary-to-generate-raw-coverage-profiling-data) )。
@ -43,7 +43,7 @@ $(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-cov show
## 查看 Cargo 构建耗时
新版本中,以下命令已经可以正常使用了:
```shell
$ cargo build --timings
$ cargo build --timings
Compiling hello-world v0.1.0 (hello-world)
Timing report saved to target/cargo-timings/cargo-timing-20220318T174818Z.html
Finished dev [unoptimized + debuginfo] target(s) in 0.98s

@ -46,7 +46,7 @@ lto = true
然后在构建时使用 `--profile` 来指定想要选择的自定义 profile
```shell
cargo build --profile release-lto
$ cargo build --profile release-lto
```
与默认的 profile 相同,自定义 profile 的编译结果也存放在 [`target/`](https://course.rs/cargo/guide/build-cache.html) 下的同名目录中,例如 `--profile release-lto` 的输出结果存储在 `target/release-lto` 中。

@ -501,7 +501,8 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; fini
其中还有一点值得注意,那就是测试模块 `tests` 的名称也出现在了最终结果中:`tests::add_two_and_two`,这是非常贴心的细节,也意味着我们可以通过**模块名称来过滤测试**
```shell
cargo test tests
$ cargo test tests
running 3 tests
test tests::add_two_and_two ... ok
test tests::add_three_and_two ... ok

@ -189,7 +189,7 @@ mod test {
```
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -85,7 +85,7 @@ mod test {
}
```
```shell
> cargo test
$ cargo test
running 18 tests
test fifth::test::into_iter ... ok
@ -149,7 +149,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
```
```shell
> cargo test
$ cargo test
error[E0521]: borrowed data escapes outside of closure
--> src\silly2.rs:47:32
@ -194,7 +194,7 @@ fn elegance() {
```
```shell
> cargo test
$ cargo test
error[E0521]: borrowed data escapes outside of closure
--> src\silly2.rs:46:17
@ -296,7 +296,7 @@ fn cell() {
```
```shell
> cargo test
$ cargo test
running 19 tests
test fifth::test::into_iter ... ok

@ -170,7 +170,7 @@ pub fn pop(&mut self) -> Option<i32> {
以上代码果不其然又报错了:
```shell
> cargo build
$ cargo build
error[E0507]: cannot move out of borrowed content
--> src/first.rs:28:15

@ -43,7 +43,7 @@ mod test {
`src/first.rs` 中添加以上测试模块,然后使用 `cargo test` 运行相关的测试用例:
```shell
> cargo test
$ cargo test
error[E0433]: failed to resolve: use of undeclared type or module `List`
--> src/first.rs:43:24
@ -150,7 +150,7 @@ impl Drop for List {
测试下上面的实现以及之前的长链表例子:
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -48,7 +48,7 @@ pub enum List {
```
```shell
> cargo build
$ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 0.22s
```

@ -51,7 +51,7 @@ fn into_iter() {
```
```shell
cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a
@ -84,7 +84,7 @@ impl<T> List<T> {
```
```shell
> cargo build
$ cargo build
```
迄今为止一切运行正常,接下来的 `next` 实现起来会有些麻烦:
@ -101,7 +101,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
```
```shell
cargo build
$ cargo build
error[E0521]: borrowed data escapes outside of closure
--> src/fourth.rs:155:13
@ -157,7 +157,8 @@ fn next(&mut self) -> Option<Self::Item> {
```
```shell
cargo build
$ cargo build
Compiling lists v0.1.0 (/Users/ABeingessner/dev/temp/lists)
error[E0521]: borrowed data escapes outside of closure
--> src/fourth.rs:159:13

@ -57,7 +57,7 @@ impl<T> List<T> {
除此之外,我们还需要处理一些关于空链表的边界问题:对于绝大部分操作而言,可能只需要使用 `head``tail` 指针,但是对于空链表,则需要同时使用它们。
一个验证方法 `methods` 是否有效的办法就是看它是否能保持不变性, 每个节点都应该有两个指针指向它: 中间的节点被它前后的节点所指向,而头部的节点除了被它后面的节点所指向外,还会被链表本身所指向,尾部的节点亦是如此。
一个验证方法 `methods` 是否有效的办法就是看它是否能保持不变性, 每个节点都应该有两个指针指向它: 中间的节点被它前后的节点所指向,而头部的节点除了被它后面的节点所指向外,还会被链表本身所指向,尾部的节点亦是如此。
```rust
pub fn push_front(&mut self, elem: T) {
@ -79,7 +79,7 @@ pub fn push_front(&mut self, elem: T) {
```
```rust
cargo build
> cargo build
error[E0609]: no field `prev` on type `std::rc::Rc<std::cell::RefCell<fourth::Node<T>>>`
--> src/fourth.rs:39:26
@ -115,7 +115,7 @@ pub fn push_front(&mut self, elem: T) {
```
```shell
> cargo build
$ cargo build
warning: field is never used: `elem`
--> src/fourth.rs:12:5
@ -152,7 +152,7 @@ pub fn pop_front(&mut self) -> Option<T> {
```
```shell
> cargo build
$ cargo build
error[E0609]: no field `elem` on type `std::rc::Rc<std::cell::RefCell<fourth::Node<T>>>`
--> src/fourth.rs:64:22
@ -180,7 +180,7 @@ pub fn pop_front(&mut self) -> Option<T> {
```
```shell
cargo build
$ cargo build
error[E0507]: cannot move out of borrowed content
--> src/fourth.rs:64:13
@ -203,7 +203,7 @@ old_head.into_inner().elem
```
```shell
> cargo build
$ cargo build
error[E0507]: cannot move out of an `Rc`
--> src/fourth.rs:64:13
@ -222,7 +222,7 @@ Rc::try_unwrap(old_head).unwrap().into_inner().elem
`Rc::try_unwrap` 返回一个 `Result`,由于我们不关心 `Err` 的情况( 如果代码合理,这里不会是 `Err` ),直接使用 `unwrap` 即可。
```shell
> cargo build
$ cargo build
error[E0599]: no method named `unwrap` found for type `std::result::Result<std::cell::RefCell<fourth::Node<T>>, std::rc::Rc<std::cell::RefCell<fourth::Node<T>>>>` in the current scope
--> src/fourth.rs:64:38
@ -242,7 +242,7 @@ Rc::try_unwrap(old_head).ok().unwrap().into_inner().elem
```
```shell
cargo build
$ cargo build
```
终于成功的运行了,下面依然是惯例 - 写几个测试用例 :
@ -283,7 +283,7 @@ mod test {
```
```shell
cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a
@ -302,7 +302,7 @@ test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured
```
## Drop
在[循环引用章节](),我们介绍过 `Rc` 最怕的就是引用形成循环,而双向链表恰恰如此。因此,当使用默认的实现来 `drop` 我们的链表时,两个节点会将各自的引用计数减少到 1 然后就不会继续减少,最终造成内存泄漏。
在[循环引用章节](),我们介绍过 `Rc` 最怕的就是引用形成循环,而双向链表恰恰如此。因此,当使用默认的实现来 `drop` 我们的链表时,两个节点会将各自的引用计数减少到 1 然后就不会继续减少,最终造成内存泄漏。
所以,这里最好的实现就是将每个节点 `pop` 出去,直到获得 `None`:
```rust

@ -20,7 +20,7 @@ pub fn peek_front(&self) -> Option<&T> {
```
```shell
cargo build
$ cargo build
error[E0515]: cannot return value referencing temporary value
--> src/fourth.rs:66:13
@ -58,7 +58,7 @@ pub fn peek_front(&self) -> Option<Ref<T>> {
```
```shell
> cargo build
$ cargo build
error[E0308]: mismatched types
--> src/fourth.rs:64:9
@ -94,7 +94,7 @@ pub fn peek_front(&self) -> Option<Ref<T>> {
```
```shell
> cargo build
$ cargo build
```
Gooood! 本章节的编译错误可以说是多个链表中最难解决的之一,依然被我们成功搞定了!
@ -114,7 +114,7 @@ fn peek() {
```
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -139,7 +139,7 @@ fn peek() {
什么?你问我这里的测试用例全吗?只能说如果测试全部的组合情况,这一章节会被撑爆。至于现在,能不出错就谢天谢地了 :(
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -18,8 +18,8 @@
#### 创建一个项目
在开始前,先来创建一个项目专门用于链表学习:
```shell
> cargo new --lib lists
> cd lists
$ cargo new --lib lists
$ cd lists
```
之后,我们会将每个一个链表放入单独的文件中,需要注意的是我们会尽量模拟真实的 Rust 开发场景:你写了一段代码,然后编译器开始跳出试图教你做事,只有这样才能真正学会 Rust温室环境是无法培养出强大的 Rustacean 的。

@ -55,7 +55,7 @@ fn into_iter() {
```
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a
@ -97,7 +97,7 @@ impl<T> Iterator for Iter<T> {
```
```shell
> cargo build
$ cargo build
error[E0106]: missing lifetime specifier
--> src/second.rs:72:18
@ -122,7 +122,7 @@ pub struct Iter<'a, T> {
```
```shell
> cargo build
$ cargo build
error[E0106]: missing lifetime specifier
--> src/second.rs:83:22
@ -163,7 +163,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
```
```shell
> cargo build
$ cargo build
error: expected `:`, found `node`
--> src/second.rs:77:47
@ -217,7 +217,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
现在,我们也许可以自信的编译下试试了:
```shell
> cargo build
$ cargo build
error[E0308]: mismatched types
--> src/second.rs:77:22
@ -260,7 +260,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
```
```shell
> cargo build
$ cargo build
Compiling lists v0.1.0 (/Users/ABeingessner/dev/temp/lists)
error[E0515]: cannot return reference to local data `*node`
@ -315,7 +315,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
```
```shell
> cargo build
$ cargo build
Compiling lists v0.1.0 (/Users/ABeingessner/dev/temp/lists)
error[E0308]: mismatched types
@ -364,7 +364,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
```
```shell
> cargo build
$ cargo build
```
🎉 🎉 🎉
@ -402,7 +402,7 @@ fn iter() {
```
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -57,7 +57,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {
```
```shell
> cargo build
$ cargo build
error[E0596]: cannot borrow `self.head` as mutable, as it is behind a `&` reference
--> src/second.rs:95:25
@ -96,7 +96,7 @@ fn next(&mut self) -> Option<Self::Item> {
```
```shell
> cargo build
$ cargo build
```
老规矩,来测试下:
@ -114,7 +114,7 @@ fn iter_mut() {
```
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -12,7 +12,7 @@ pub fn peek(&self) -> Option<&T> {
```
```shell
> cargo build
$ cargo build
error[E0515]: cannot return reference to local data `node.elem`
--> src/second.rs:37:13
@ -46,7 +46,7 @@ pub fn peek(&self) -> Option<&T> {
```
```shell
> cargo build
$ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 0.32s
```
@ -81,7 +81,7 @@ fn peek() {
```
```shell
> cargo test
$ cargo test
error[E0384]: cannot assign twice to immutable variable `value`
--> src/second.rs:100:13
@ -124,7 +124,7 @@ fn peek() {
这次我们直接匹配出来可变引用 `value`,然后对其修改即可。
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -126,7 +126,7 @@ pub fn pop(&mut self) -> Option<i32> {
不错,看上去简洁了很多,下面运行下测试代码确保链表依然可以正常运行(这就是 TDD 的优点!) :
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a
@ -188,7 +188,7 @@ impl<T> Drop for List<T> {
大家在修改了 `List` 的定义后,别忘了将 `impl` 中的 `List` 修改为 `List<T>`,切记**泛型参数也是类型定义的一部分**。
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -49,7 +49,8 @@ list3 -> X ---+
测试下新的代码:
```shell
cargo test
$ cargo test
Compiling lists v0.1.0 (/Users/ABeingessner/dev/too-many-lists/lists)
Finished dev [unoptimized + debuginfo] target(s) in 1.10s
Running /Users/ABeingessner/dev/too-many-lists/lists/target/debug/deps/lists-86544f1d97438f1f

@ -74,7 +74,7 @@ pub fn prepend(&self, elem: T) -> List<T> {
运行下试试:
```shell
> cargo build
$ cargo build
warning: field is never used: `elem`
--> src/third.rs:10:5
@ -101,7 +101,7 @@ pub fn tail(&self) -> List<T> {
```
```shell
cargo build
$ cargo build
error[E0308]: mismatched types
--> src/third.rs:27:22
@ -159,7 +159,7 @@ mod test {
```
```shell
> cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a
@ -211,7 +211,7 @@ fn iter() {
```
```shell
cargo test
$ cargo test
Running target/debug/lists-5c71138492ad4b4a

@ -13,7 +13,7 @@ impl<T> List<T> {
但是我们不再在 `tail` 中使用 `Option`:
```shell
> cargo build
$ cargo build
error[E0308]: mismatched types
--> src/fifth.rs:15:34
@ -73,7 +73,7 @@ pub fn push(&mut self, elem: T) {
```
```shell
> cargo build
$ cargo build
error[E0609]: no field `next` on type `*mut fifth::Node<T>`
--> src/fifth.rs:31:23
@ -91,7 +91,7 @@ error[E0609]: no field `next` on type `*mut fifth::Node<T>`
```
```shell
> cargo build
$ cargo build
error[E0609]: no field `next` on type `*mut fifth::Node<T>`
--> src/fifth.rs:31:23
@ -109,7 +109,7 @@ error[E0609]: no field `next` on type `*mut fifth::Node<T>`
```
```shell
> cargo build
$ cargo build
error[E0133]: dereference of raw pointer is unsafe and requires
unsafe function or block
@ -149,7 +149,7 @@ pub fn push(&mut self, elem: T) {
```
```shell
> cargo build
$ cargo build
warning: field is never used: `elem`
--> src/fifth.rs:11:5
|
@ -225,7 +225,7 @@ mod test {
摊牌了,我们偷懒了,这些测试就是从之前的栈链表赋值过来的,但是依然做了些改变,例如在末尾增加了几个步骤以确保在 `pop` 中不会发生尾指针损坏( tail-pointer corruption )的情况。
```shell
cargo test
$ cargo test
running 12 tests
test fifth::test::basics ... ok

@ -82,7 +82,7 @@ impl<T> List<T> {
但是如果你担心不再能看到错误,那就纯属多余了:
```shell
> cargo build
$ cargo build
error[E0382]: use of moved value: `new_tail`
--> src/fifth.rs:38:38
@ -139,7 +139,7 @@ impl<T> List<T> {
```
```shell
> cargo build
$ cargo build
error[E0106]: missing lifetime specifier
--> src/fifth.rs:3:18
@ -190,7 +190,7 @@ impl<'a, T> List<'a, T> {
```
```shell
cargo build
$ cargo build
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/fifth.rs:35:27
@ -235,7 +235,7 @@ pub fn push(&'a mut self, elem: T) {
当当当当,成功通过编译:
```shell
cargo build
$ cargo build
warning: field is never used: `elem`
--> src/fifth.rs:9:5
@ -297,7 +297,7 @@ mod test {
}
```
```shell
cargo test
$ cargo test
error[E0499]: cannot borrow `list` as mutable more than once at a time
--> src/fifth.rs:68:9

@ -196,7 +196,7 @@ mod test {
```
```shell
cargo test
$ cargo test
running 12 tests
test fifth::test::basics ... ok

@ -36,7 +36,7 @@ info: installing component 'miri'
> + 是一种临时性的规则运用,如果你不想每次都使用 `+nightly-2022-01-21`,可以使用 [`rustup override set`](https://course.rs/appendix/rust-version.html#rustup-和-rust-nightly-的职责) 命令对当前项目的 Rust 版本进行覆盖
```shell
> cargo +nightly-2022-01-21 miri test
$ cargo +nightly-2022-01-21 miri test
I will run `"cargo.exe" "install" "xargo"` to install
a recent enough xargo. Proceed? [Y/n]
@ -146,7 +146,7 @@ UB 检测是必须的,因为它发生在运行时,因此很难发现,如
总之,`miri` 的使用很简单:
```shell
> cargo +nightly-2022-01-21 miri test
$ cargo +nightly-2022-01-21 miri test
```
下面来看看具体的错误:

@ -50,7 +50,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
Compiling miri-sandbox v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 0.71s
Running `target\debug\miri-sandbox.exe`
@ -101,7 +102,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
22
```
@ -141,7 +143,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
20
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run
@ -172,7 +175,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
[3, 3, 0, 0, 0, 0, 0, 0, 0, 0]
```
@ -206,7 +210,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
[6, 0, 0, 0, 0, 0, 0, 0, 0, 0]
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run
@ -238,7 +243,7 @@ unsafe {
```
```shell
cargo run
$ cargo run
[20, 0, 0, 0, 0, 0, 0, 0, 0, 0]
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run
@ -310,7 +315,7 @@ unsafe {
```
```shell
cargo run
$ cargo run
[10, 12, 0, 0, 0, 0, 0, 0, 0, 0]
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run
@ -353,7 +358,7 @@ unsafe {
```
```shell
cargo run
$ cargo run
[8, 12, 4, 6, 8, 10, 12, 14, 16, 18]
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run
@ -393,7 +398,7 @@ unsafe {
```
```shell
cargo run
$ cargo run
warning: unnecessary `unsafe` block
--> src\main.rs:6:1
@ -436,7 +441,7 @@ unsafe {
```
```shell
cargo run
$ cargo run
error[E0606]: casting `&i32` as `*mut i32` is invalid
--> src/main.rs:11:20
@ -454,7 +459,7 @@ let ptr4 = sref3 as *const i32 as *mut i32;
如上,先将不可变引用转换成不可变的裸指针,然后再转换成可变的裸指针。
```shell
cargo run
$ cargo run
14
17
@ -502,7 +507,8 @@ unsafe {
可以看到,我们其实可以创建一个可变的裸指针,只要不去使用写操作,而是只使用读操作。
```shell
cargo run
$ cargo run
10
10
13
@ -534,7 +540,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
12
13
@ -578,7 +585,8 @@ unsafe {
地狱一般的代码,就等着 miri 来优化你吧。
```shell
cargo run
$ cargo run
16
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run
@ -624,7 +632,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
12
16
@ -666,7 +675,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
13
16
@ -694,7 +704,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
21
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run
@ -726,7 +737,8 @@ unsafe {
```
```shell
cargo run
$ cargo run
21
MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo +nightly-2022-01-21 miri run

Loading…
Cancel
Save