upadte img sources

pull/408/head
sunface 3 years ago
parent 37a9e7ac9d
commit 698626c2be

@ -28,7 +28,7 @@ fn main() {}
这里我们创建一个有些复杂的枚举类型 `List`,这个类型很有意思,它的每个值都指向了另一个 `List`,此外,得益于 `Rc` 的使用还允许多个值指向一个 `List` 这里我们创建一个有些复杂的枚举类型 `List`,这个类型很有意思,它的每个值都指向了另一个 `List`,此外,得益于 `Rc` 的使用还允许多个值指向一个 `List`
<img alt="" src="/img/self-ref-01.png" class="center" /> <img alt="" src="https://pica.zhimg.com/80/v2-0db007dfb4167ebc22f50cf5b5a85f53_1440w.png" class="center" />
如上图所示,每个矩形框节点都是一个 `List` 类型,它们或者是拥有值且指向另一个 `List` 的`Cons`,或者是一个没有值的终结点 `Nil`。同时,由于 `RefCell` 的使用,每个 `List` 所指向的 `List` 还能够被修改。 如上图所示,每个矩形框节点都是一个 `List` 类型,它们或者是拥有值且指向另一个 `List` 的`Cons`,或者是一个没有值的终结点 `Nil`。同时,由于 `RefCell` 的使用,每个 `List` 所指向的 `List` 还能够被修改。
@ -81,7 +81,7 @@ b指向的节点 = Some(RefCell { value: Cons(5, RefCell { value: Nil }) })
`main` 函数结束前,`a` 和 `b` 的引用计数均是 `2`,随后 `b` 触发 `Drop`,此时引用计数会变为 `1`,并不会归 `0`,因此 `b` 所指向内存不会被释放,同理可得 `a` 指向的内存也不会被释放,最终发生了内存泄漏。 `main` 函数结束前,`a` 和 `b` 的引用计数均是 `2`,随后 `b` 触发 `Drop`,此时引用计数会变为 `1`,并不会归 `0`,因此 `b` 所指向内存不会被释放,同理可得 `a` 指向的内存也不会被释放,最终发生了内存泄漏。
下面一张图很好的展示了这种引用循环关系: 下面一张图很好的展示了这种引用循环关系:
<img alt="" src="/img/self-ref-02.png" class="center" /> <img alt="" src="https://pic1.zhimg.com/80/v2-2dbfc981f05019bf70bf81c93f956c35_1440w.png" class="center" />
现在我们还需要轻轻的推一下,让塔米诺骨牌轰然倒塌。反注释最后一行代码,试着运行下: 现在我们还需要轻轻的推一下,让塔米诺骨牌轰然倒塌。反注释最后一行代码,试着运行下:
```console ```console

@ -6,7 +6,7 @@
`Erlang` 之父[`Joe Armstrong`](https://en.wikipedia.org/wiki/Joe_Armstrong_(programmer))(伟大的异步编程先驱,开创一个时代的殿堂级计算机科学家,我还犹记得当年刚学到 `Erlang` 时的震撼respect用一张5岁小孩都能看到的图片解释了并发与并行的区别 `Erlang` 之父[`Joe Armstrong`](https://en.wikipedia.org/wiki/Joe_Armstrong_(programmer))(伟大的异步编程先驱,开创一个时代的殿堂级计算机科学家,我还犹记得当年刚学到 `Erlang` 时的震撼respect用一张5岁小孩都能看到的图片解释了并发与并行的区别
<img alt="" src="/img/threads-01.png" class="center" /> <img alt="" src="https://pic1.zhimg.com/80/f37dd89173715d0e21546ea171c8a915_1440w.png" class="center" />
上图很直观的体现了: 上图很直观的体现了:

@ -246,7 +246,7 @@ for handle in handles {
下图是该代码在 `48` 核机器上的运行结果: 下图是该代码在 `48` 核机器上的运行结果:
<img alt="" src="/img/threads-02.png" class="center" /> <img alt="" src="https://pic3.zhimg.com/80/v2-af225672de09c0e377023f5f39dd87eb_1440w.png" class="center" />
从图上可以明显的看出: 吞吐并不是线性增长,尤其从 `16` 核开始,甚至开始肉眼可见的下降,这是为什么呢? 从图上可以明显的看出: 吞吐并不是线性增长,尤其从 `16` 核开始,甚至开始肉眼可见的下降,这是为什么呢?

@ -3,7 +3,7 @@
我们先通过一张web框架性能对比图来感受下 Rust 异步编程的性能: 我们先通过一张web框架性能对比图来感受下 Rust 异步编程的性能:
<img alt="actix-vs-gin screenshot" width="100%" src="/img/async-01.png" class="center" /> <img alt="actix-vs-gin screenshot" width="100%" src="https://pic1.zhimg.com/v2-3cebd732fb56f43713f106fdcfa44a3c_b.png" class="center" />
上图并不能说 Rust 写的 `actix` 框架比 Go 的 `gin` 更好、更优秀,但是确实可以一定程度上说明 Rust 的异步性能非常的高! 上图并不能说 Rust 写的 `actix` 框架比 Go 的 `gin` 更好、更优秀,但是确实可以一定程度上说明 Rust 的异步性能非常的高!

@ -109,7 +109,7 @@ pub struct Pin<P> {
它包裹一个指针,并且能确保该指针指向的数据不会被移动,例如 `Pin<&mut T>` , `Pin<&T>` , `Pin<Box<T>>` ,都能确保 `T` 不会被移动。 它包裹一个指针,并且能确保该指针指向的数据不会被移动,例如 `Pin<&mut T>` , `Pin<&T>` , `Pin<Box<T>>` ,都能确保 `T` 不会被移动。
<img alt="" src="/img/async-03.png" class="center" /> <img alt="" src="https://pic1.zhimg.com/80/v2-de79f3a7a401588d671ecd121916cd90_1440w.png" class="center" />
`Unpin` 才是一个特征,它表明一个类型可以随意被移动,那么问题来了,可以被 `Pin` 住的值,它有没有实现什么特征呢? 答案很出乎意料,可以被 `Pin` 住的值实现的特征是 `!Unpin` ,大家可能之前没有见过,但是它其实很简单,`!` 代表没有实现某个特征的意思,`!Unpin` 说明类型没有实现 `Unpin` 特征,那自然就可以被 `Pin` 了。 `Unpin` 才是一个特征,它表明一个类型可以随意被移动,那么问题来了,可以被 `Pin` 住的值,它有没有实现什么特征呢? 答案很出乎意料,可以被 `Pin` 住的值实现的特征是 `!Unpin` ,大家可能之前没有见过,但是它其实很简单,`!` 代表没有实现某个特征的意思,`!Unpin` 说明类型没有实现 `Unpin` 特征,那自然就可以被 `Pin` 了。
@ -228,7 +228,7 @@ fn main() {
下面的图片也可以帮助更好的理解这个过程: 下面的图片也可以帮助更好的理解这个过程:
<img alt="" src="/img/async-02.jpg" class="center" /> <img alt="" src="https://pica.zhimg.com/80/v2-eaeb33da283dc1063b862d2307821976_1440w.jpg" class="center" />
## Pin 在实践中的运用 ## Pin 在实践中的运用
在理解了 `Pin` 的作用后,我们再来看看它怎么帮我们解决问题。 在理解了 `Pin` 的作用后,我们再来看看它怎么帮我们解决问题。

@ -12,7 +12,7 @@ fn add(i: i32, j: i32) -> i32 {
该函数如此简单,但是又是如此的五脏俱全,声明函数的关键字 `fn` ,函数名 `add()`,参数 `i``j`,参数类型和返回值类型都是 `i32`,总之一切那么的普通,但是又那么的自信,直到你看到了下面这张图: 该函数如此简单,但是又是如此的五脏俱全,声明函数的关键字 `fn` ,函数名 `add()`,参数 `i``j`,参数类型和返回值类型都是 `i32`,总之一切那么的普通,但是又那么的自信,直到你看到了下面这张图:
<img alt="" src="/img/function-01.png" class="center" /> <img alt="" src="https://pic2.zhimg.com/80/v2-54b3a6d435d2482243edc4be9ab98153_1440w.png" class="center" />
当你看懂了这张图,其实就等于差不多完成了函数章节的学习,但是这么短的章节显然对不起读者老爷们的厚爱,所以我们来展开下。 当你看懂了这张图,其实就等于差不多完成了函数章节的学习,但是这么短的章节显然对不起读者老爷们的厚爱,所以我们来展开下。

@ -51,7 +51,7 @@ let world = &s[6..11];
对于 `let world = &s[6..11];` 来说,`world` 是一个切片,该切片的指针指向 `s` 的第 7 个字节(索引从 0 开始, 6 是第 7 个字节),且该切片的长度是 `5` 个字节。 对于 `let world = &s[6..11];` 来说,`world` 是一个切片,该切片的指针指向 `s` 的第 7 个字节(索引从 0 开始, 6 是第 7 个字节),且该切片的长度是 `5` 个字节。
<img alt="" src="/img/string-01.svg" class="center" style="width: 50%;" /> <img alt="" src="https://pic1.zhimg.com/80/v2-69da917741b2c610732d8526a9cc86f5_1440w.jpg" class="center" style="width: 50%;" />
在使用 Rust 的 `..` [range序列](../base-type/numbers.md#序列(Range))语法时,如果你想从索引 0 开始,可以使用如下的方式,这两个是等效的: 在使用 Rust 的 `..` [range序列](../base-type/numbers.md#序列(Range))语法时,如果你想从索引 0 开始,可以使用如下的方式,这两个是等效的:
```rust ```rust

@ -162,7 +162,7 @@ println!("{:?}", user1);
``` ```
上面定义的 `File` 结构体在内存中的排列如下图所示: 上面定义的 `File` 结构体在内存中的排列如下图所示:
<img alt="" src="/img/struct-01.png" class="center" /> <img alt="" src="https://pic3.zhimg.com/80/v2-8cc4ed8cd06d60f974d06ca2199b8df5_1440w.png" class="center" />
从图中可以清晰的看出 `File` 结构体两个字段 `name``data` 分别拥有底层两个 `[u8]` 数组的所有权(`String` 类型的底层也是 `[u8]` 数组),通过 `ptr` 指针指向底层数组的内存地址,这里你可以把 `ptr` 指针理解为 Rust 中的引用类型。 从图中可以清晰的看出 `File` 结构体两个字段 `name``data` 分别拥有底层两个 `[u8]` 数组的所有权(`String` 类型的底层也是 `[u8]` 数组),通过 `ptr` 指针指向底层数组的内存地址,这里你可以把 `ptr` 指针理解为 Rust 中的引用类型。

@ -36,7 +36,7 @@ impl Circle {
我们这里先不详细展开讲解,只是先建立对方法定义的大致印象。下面的图片将 Rust 方法定义与其它语言的方法定义做了对比: 我们这里先不详细展开讲解,只是先建立对方法定义的大致印象。下面的图片将 Rust 方法定义与其它语言的方法定义做了对比:
<img alt="" src="/img/method-01.png" class="center"/> <img alt="" src="https://pica.zhimg.com/80/v2-0d848e960f3279999eab4b1317f6538e_1440w.png" class="center"/>
可以看出,其它语言中所有定义都在 `class` 中,但是 Rust 的对象定义和方法定义是分离的,这种数据和使用分离的方式,会给予使用者极高的灵活度。 可以看出,其它语言中所有定义都在 `class` 中,但是 Rust 的对象定义和方法定义是分离的,这种数据和使用分离的方式,会给予使用者极高的灵活度。

@ -58,7 +58,7 @@ fn calculate_length(s: &String) -> usize {
2. `calculate_length` 的参数 `s` 类型从 `String` 变为 `&String` 2. `calculate_length` 的参数 `s` 类型从 `String` 变为 `&String`
这里,`&` 符号即是引用,它们允许你使用值,但是不获取所有权,如图所示: 这里,`&` 符号即是引用,它们允许你使用值,但是不获取所有权,如图所示:
<img alt="&String s pointing at String s1" src="/img/borrowing-01.svg" class="center" /> <img alt="&String s pointing at String s1" src="https://pic1.zhimg.com/80/v2-fc68ea4a1fe2e3fe4c5bb523a0a8247c_1440w.jpg" class="center" />
通过 `&s1` 语法,我们创建了一个 **指向s1的引用**,但是并不拥有它。因为并不拥有这个值,当引用离开作用域后,其指向的值也不会被丢弃。 通过 `&s1` 语法,我们创建了一个 **指向s1的引用**,但是并不拥有它。因为并不拥有这个值,当引用离开作用域后,其指向的值也不会被丢弃。

@ -190,7 +190,7 @@ error[E0382]: use of moved value: `s1`
如果你在其他语言中听说过术语**浅拷贝( shallow copy )**和**深拷贝( deep copy )**,那么拷贝指针、长度和容量而不拷贝数据听起来就像浅拷贝,但是又因为 Rust 同时使第一个变量 `s1` 无效了,因此这个操作被称为**移动move**,而不是浅拷贝。上面的例子可以解读为 `s1` 被**移动**到了 `s2` 中。那么具体发生了什么,用一张图简单说明: 如果你在其他语言中听说过术语**浅拷贝( shallow copy )**和**深拷贝( deep copy )**,那么拷贝指针、长度和容量而不拷贝数据听起来就像浅拷贝,但是又因为 Rust 同时使第一个变量 `s1` 无效了,因此这个操作被称为**移动move**,而不是浅拷贝。上面的例子可以解读为 `s1` 被**移动**到了 `s2` 中。那么具体发生了什么,用一张图简单说明:
<img alt="s1 moved to s2" src="/img/ownership01.svg" class="center" style="width: 50%;" /> <img alt="s1 moved to s2" src="https://pic1.zhimg.com/80/v2-3ec77951de6a17584b5eb4a3838b4b61_1440w.jpg" class="center" style="width: 50%;" />
这样就解决了我们之前的问题,`s1` 不再指向任何数据,只有 `s2` 是有效的,当 `s2` 离开作用域,它就会释放内存。 相信此刻,你应该明白了,为什么 Rust 称呼 `let a = b` 为**变量绑定**了吧? 这样就解决了我们之前的问题,`s1` 不再指向任何数据,只有 `s2` 是有效的,当 `s2` 离开作用域,它就会释放内存。 相信此刻,你应该明白了,为什么 Rust 称呼 `let a = b` 为**变量绑定**了吧?

@ -263,7 +263,7 @@ help: function arguments must have a statically known size, borrowed types alway
下面这张图很好的解释了静态分发 `Box<T>` 和动态分发 `Box<dyn Trait>` 的区别: 下面这张图很好的解释了静态分发 `Box<T>` 和动态分发 `Box<dyn Trait>` 的区别:
<img alt="" src="/img/trait-object-01.svg" class="center" /> <img alt="" src="https://pic1.zhimg.com/80/v2-b771fe4cfc6ebd63d9aff42840eb8e67_1440w.jpg" class="center" />
## Self与self ## Self与self
在 Rust 中,有两个`self`,一个指代当前的实例对象,一个指代特征或者方法类型的别名: 在 Rust 中,有两个`self`,一个指代当前的实例对象,一个指代特征或者方法类型的别名:

@ -44,7 +44,7 @@ tokio是一个纸醉金迷之地只要有钱就可以为所欲为
因为快所以快,前者是 Rust 快,后者是 `tokio` 快。 `tokio` 在编写时充分利用了 Rust 提供的各种零成本抽象和高性能特性,而且贯彻了 Rust 的牛逼思想:如果你选择手写代码,那么最好的结果就是跟 `tokio` 一样快! 因为快所以快,前者是 Rust 快,后者是 `tokio` 快。 `tokio` 在编写时充分利用了 Rust 提供的各种零成本抽象和高性能特性,而且贯彻了 Rust 的牛逼思想:如果你选择手写代码,那么最好的结果就是跟 `tokio` 一样快!
以下是一张官方提供的性能参考图,大致能体现出 `tokio` 的性能之恐怖: 以下是一张官方提供的性能参考图,大致能体现出 `tokio` 的性能之恐怖:
<img alt="tokio performance" src="/img/tokio-01.png" class="center" /> <img alt="tokio performance" src="https://pica.zhimg.com/80/v2-5f5ca10550ec936427c2919191331ae8_1440w.png" class="center" />
**高可靠** **高可靠**

Loading…
Cancel
Save