Merge branch 'sunface:main' into ShoreCN-patch-1

pull/1312/head
ShoreCN 2 years ago committed by GitHub
commit 6439136879
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -376,3 +376,4 @@
- [1.70](appendix/rust-versions/1.70.md)
- [1.71](appendix/rust-versions/1.71.md)
- [1.72](appendix/rust-versions/1.72.md)
- [1.73](appendix/rust-versions/1.73.md)

@ -347,7 +347,7 @@ impl Future for Delay {
#### 处理 wake 通知
下面,让我们更新 mint-tokio 服务,让它能接收 wake 通知:当 `waker.wake()` 被调用后,相关联的任务会被放入执行器的队列中,然后等待执行器的调用执行。
下面,让我们更新 mini-tokio 服务,让它能接收 wake 通知:当 `waker.wake()` 被调用后,相关联的任务会被放入执行器的队列中,然后等待执行器的调用执行。
为了实现这一点,我们将使用消息通道来排队存储这些被唤醒并等待调度的任务。有一点需要注意,从消息通道接收消息的线程(执行器所在的线程)和发送消息的线程(唤醒任务时所在的线程)可能是不同的,因此消息( `Waker` )必须要实现 `Send``Sync`,才能跨线程使用。
@ -522,7 +522,7 @@ async fn main() {
我们之前的 `Delay` 实现中,会在每一次 `poll` 调用时都生成一个新的线程。这么做问题不大,但是当 `poll` 调用较多时会出现明显的性能问题!一个解决方法就是记录你是否已经生成了一个线程,然后只有在没有生成时才去创建一个新的线程。但是一旦这么做,就必须确保线程的 `Waker` 在后续 `poll` 调用中被正确更新,否则你无法唤醒最近的 `Waker`
这一段大家可能会看得云里雾里的,没办法,原文就来绕去,好在终于可以看代码了。。我们可以通过代码来解决疑惑:
这一段大家可能会看得云里雾里的,没办法,原文就来绕去,好在终于可以看代码了。。我们可以通过代码来解决疑惑:
```rust
use std::future::Future;

@ -73,7 +73,7 @@ async fn main() {
Tokio 提供了多种消息通道,可以满足不同场景的需求:
- [`mpsc`](https://docs.rs/tokio/1.15.0/tokio/sync/mpsc/index.html), 多生产者,单消费者模式
- [`oneshot`](https://docs.rs/tokio/1.15.0/tokio/sync/oneshot/index.html), 单生产者单消费,一次只能发送一条消息
- [`oneshot`](https://docs.rs/tokio/1.15.0/tokio/sync/oneshot/index.html), 单生产者单消费,一次只能发送一条消息
- [`broadcast`](https://docs.rs/tokio/1/tokio/sync/broadcast/index.html),多生产者,多消费者,其中每一条发送的消息都可以被所有接收者收到,因此是广播
- [`watch`](https://docs.rs/tokio/1/tokio/sync/watch/index.html),单生产者,多消费者,只保存一条最新的消息,因此接收者只能看到最近的一条消息,例如,这种模式适用于配置文件变化的监听

@ -247,7 +247,7 @@ impl ThreadPool {
### 存储线程
创建 `ThreadPool` 后,下一步就是存储具体的线程,既然要存放线程,一个绕不过去的问题就是:用什么类型来存放,例如假如使用 `Vect<T>` 来存储,那这个 `T` 应该是什么?
创建 `ThreadPool` 后,下一步就是存储具体的线程,既然要存放线程,一个绕不过去的问题就是:用什么类型来存放,例如假如使用 `Vec<T>` 来存储,那这个 `T` 应该是什么?
估计还得探索下 `thread::spawn` 的签名,毕竟它生成并返回一个线程:

@ -435,7 +435,7 @@ let val = v.iter()
// 每两个元素剔除一个
// [1, 3, 5]
.filter(|&(idx, _)| idx % 2 == 0)
.map(|(idx, val)| val)
.map(|(_, val)| val)
// 累加 1+3+5 = 9
.fold(0u64, |sum, acm| sum + acm);

@ -449,9 +449,9 @@ fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
- `#name` 可能是一个表达式,我们需要它的字面值形式
- 可以减少一次 `String` 带来的内存分配
在运行之前,可以显示用 expand 展开宏,观察是否有错误或是否符合预期:
在运行之前,可以先用 expand 展开宏,观察是否有错误或符合预期:
```shell
$ cargo expand --lib hello_macro
$ cargo expand --bin hello_macro
```
```rust
struct Sunfei;

@ -144,7 +144,7 @@ fn main() {
}
```
上面的代码会报错,因为我们不能对一个不可变的值进行可变借用,这会破坏 Rust 的安全性保证,相反,你可以对一个可变值进行不可变借用。原因是:当值不可变时,可能会有多个不可变的引用指向它,此时若将修改其中一个为可变的,会造成可变引用与不可变引用共存的情况;而当值可变时,最多只会有一个可变引用指向它,将其修改为不可变,那么最终依然是只有一个不可变的引用指向它。
上面的代码会报错,因为我们不能对一个不可变的值进行可变借用,这会破坏 Rust 的安全性保证,相反,你可以对一个可变值进行不可变借用。原因是:当值不可变时,可能会有多个不可变的引用指向它,此时若将其中一个修改为可变的,会造成可变引用与不可变引用共存的情况;而当值可变时,最多只会有一个可变引用指向它,将其修改为不可变,那么最终依然是只有一个不可变的引用指向它。
虽然基本借用规则是 Rust 的基石,然而在某些场景中,一个值可以在其方法内部被修改,同时对于其它代码不可变,是很有用的:

@ -41,7 +41,7 @@ error: could not compile `my-project` (bin "my-project") due to previous error
几个原本由 Clippy 提供的 lints提升到 rustc 里:
* [`clippy::undropped_manually_drops`](https://rust-lang.github.io/rust-clippy/rust-1.71.0/index.html#undropped_manually_drops) => [undropped-manually-drops](https://doc.rust-lang.org/1.72.0/rustc/lints/listing/deny-by-default.html#undropped-manually-drops) (deny)
* [`clippy::undropped_manually_drops`](https://rust-lang.github.io/rust-clippy/rust-1.71.0/index.html#undropped_manually_drops) => [`undropped-manually-drops`](https://doc.rust-lang.org/1.72.0/rustc/lints/listing/deny-by-default.html#undropped-manually-drops) (deny)
* 无作用的 `ManullyDrop`
* [`clippy::invalid_utf8_in_unchecked`](https://rust-lang.github.io/rust-clippy/rust-1.71.0/index.html#invalid_utf8_in_unchecked) => [`invalid_from_utf8_unchecked`](https://doc.rust-lang.org/1.72.0/rustc/lints/listing/deny-by-default.html#invalid-from-utf8-unchecked) (deny) 或 [`invalid_from_utf8`](https://doc.rust-lang.org/1.72.0/rustc/lints/listing/warn-by-default.html#invalid-from-utf8) (warn)
* 检查调用 `std::str::from_utf8_unchecked``std::str::from_utf8_unchecked_mut` 转换不合法的 UTF-8 字面量,这会违反了 safety 前提,导致未定义行为

@ -0,0 +1,84 @@
# Rust 新版解读 | 1.73 | panic 报错展示优化
> Rust 1.73 官方 release doc: [Announcing Rust 1.73.0 | Rust Blog](https://blog.rust-lang.org/2023/10/05/Rust-1.73.0.html)
通过 [rustup](https://www.rust-lang.org/tools/install) 安装的同学可以使用以下命令升级到 1.73 版本:
```shell
$ rustup update stable
```
## 更简洁的 panic 报错信息
默认的 panic handler 会把报错信息单独列出一行,当报错信息很长、包含多行或者嵌套结构的时候可读性会更强。
```rust
fn main() {
let file = "ferris.txt";
panic!("oh no! {file:?} not found!");
}
```
Rust 1.73 之前的:
```shell
thread 'main' panicked at 'oh no! "ferris.txt" not found!', src/main.rs:3:5
```
Rust 1.73 之后的:
```shell
thread 'main' panicked at src/main.rs:3:5:
oh no! "ferris.txt" not found!
```
另外,由 `assert_eq``assert_ne` 产生的 panic 消息也把自定义信息部分(第三个参数)的展示位置改动了一下:
```rust
fn main() {
assert_eq!("🦀", "🐟", "ferris is not a fish");
}
```
Rust 1.73 之前的:
```shell
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `"🦀"`,
right: `"🐟"`: ferris is not a fish', src/main.rs:2:5
```
Rust 1.73 之后的:
```shell
thread 'main' panicked at src/main.rs:2:5:
assertion `left == right` failed: ferris is not a fish
left: "🦀"
right: "🐟"
```
## 线程局部初始化
如 [RFC 3184](https://github.com/rust-lang/rfcs/blob/master/text/3184-thread-local-cell-methods.md) 提案, `LocalKey<Cell<T>>``LocalKey<RefCell<T>>` 现在可以直接用 `get()`, `set()`, `take()``replace()` 方法来操作,不再需要写 `with(|inner|...)` 的闭包形式。声明线程静态局部变量的宏 `thread_local!` 内部就是使用的就是 `LocalKey<T>`
新的方法让代码更简洁,也避免了默认值在新线程运行额外的初始化代码。
```rust
thread_local! {
static THINGS: Cell<Vec<i32>> = Cell::new(Vec::new());
}
fn f() {
// before:
THINGS.with(|i| i.set(vec![1, 2, 3]));
// now:
THINGS.set(vec![1, 2, 3]);
// ...
// before:
let v = THINGS.with(|i| i.take());
// now:
let v: Vec<i32> = THINGS.take();
}
```
## Others
其它更新细节和稳定的API列表参考[原Blog](https://blog.rust-lang.org/2023/10/05/Rust-1.73.0.html#stabilized-apis)

@ -41,6 +41,7 @@ fn main() {
}
fn print_suit(card: PokerSuit) {
// 需要在定义 enum PokerSuit 的上面添加上 #[derive(Debug)],否则会报 card 没有实现 Debug
println!("{:?}",card);
}
```

@ -349,7 +349,7 @@ error[E0583]: file not found for module `front_of_house`
是的,如果需要将文件夹作为一个模块,我们需要进行显示指定暴露哪些子模块。按照上述的报错信息,我们有两种方法:
- 在 `front_of_house` 目录里创建一个 `mod.rs`,如果你使用的 `rustc` 版本 `1.30` 之前,这是唯一的方法。
- 在 `front_of_house` 同级目录里创建一个与模块(目录)同名的 rs 文件 `front_of_house.rs`,在新版本里,更建议使用这样的命名方式来避免项目中存在大量同名的 `mod.rs` 文件( Python 点了个 `踩`)。
- 在 `front_of_house` **同级**目录里创建一个与模块(目录)**同名**的 rs 文件 `front_of_house.rs`,在新版本里,更建议使用这样的命名方式来避免项目中存在大量同名的 `mod.rs` 文件( Python 点了个 `踩`)。
而无论是上述哪个方式创建的文件,其内容都是一样的,你需要定义你的子模块(子模块名与文件名相同):

@ -98,7 +98,7 @@ let s = "hello";
} // 此作用域已结束s不再有效
```
简而言之,`s` 从创建伊始就开始有效然后有效期持续到它离开作用域为止可以看出就作用域来说Rust 语言跟其他编程语言没有区别。
简而言之,`s` 从创建开始有效然后有效期持续到它离开作用域为止可以看出就作用域来说Rust 语言跟其他编程语言没有区别。
#### 简单介绍 String 类型
@ -181,17 +181,24 @@ println!("{}, world!", s1);
由于 Rust 禁止你使用无效的引用,你会看到以下的错误:
```console
error[E0382]: use of moved value: `s1`
error[E0382]: borrow of moved value: `s1`
--> src/main.rs:5:28
|
2 | let s1 = String::from("hello");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 | let s2 = s1;
| -- value moved here
4 |
5 | println!("{}, world!", s1);
| ^^ value used here after move
| ^^ value borrowed here after move
|
= note: move occurs because `s1` has type `std::string::String`, which does
not implement the `Copy` trait
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
3 | let s2 = s1.clone();
| ++++++++
For more information about this error, try `rustc --explain E0382`.
```
现在再回头看看之前的规则,相信大家已经有了更深刻的理解:

@ -61,7 +61,7 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
以上信息包含了两条重要信息:
- `main` 函数所在的线程崩溃了,发生的代码位置是 `src/main.rs` 中的第 2 行第 5 个字符(去除该行前面的空字符)
- `main` 函数所在的线程崩溃了,发生的代码位置是 `src/main.rs` 中的第 2 行第 5 个字符(包含该行前面的空字符)
- 在使用时加上一个环境变量可以获取更详细的栈展开信息:
- Linux/macOS 等 UNIX 系统: `RUST_BACKTRACE=1 cargo run`
- Windows 系统PowerShell `$env:RUST_BACKTRACE=1 ; cargo run`

@ -118,7 +118,7 @@ fn main() {
大家猜猜哪一行会输出 :) 至于 `NaN` 为何不能比较,这个原因就比较复杂了( 有读者会说,其实就是你不知道,我只能义正严辞的说:咦?你怎么知道 :P )。
既然浮点数有一个值不可以比较相等性,那它自然只能实现 `PartialEq` 而不能实现 `Eq` 了,以此类推,如果我们的类型也有这种特殊要求,那也应该这么
既然浮点数有一个值不可以比较相等性,那它自然只能实现 `PartialEq` 而不能实现 `Eq` 了,以此类推,如果我们的类型也有这种特殊要求,那也应该这么
### Ord 和 PartialOrd
事实上,还有一对与 `Eq/PartialEq` 非常类似的特征,它们可以用于 `<`、`<=`、`>` 和 `>=` 比较,至于哪个类型实现了 `PartialOrd` 却没有实现 `Ord` 就交给大家自己来思考了:)

@ -43,7 +43,7 @@
* ORM
* [rbatis/rbatis](https://github.com/rbatis/rbatis) 国内团队开发的ORM异步、性能高、简单易上手
* [diesel-rs/diesel](https://github.com/diesel-rs/diesel) 安全、扩展性强的Rust ORM库支持`MySQL`、`PostgreSQL`、`SQLLite`
* [diesel-rs/diesel](https://github.com/diesel-rs/diesel) 安全、扩展性强的Rust ORM库支持`MySQL`、`PostgreSQL`、`SQLite`
* MySQL
* [blackbeam/rust-mysql-simple](https://github.com/blackbeam/rust-mysql-simple) 纯Rust实现的MySQL驱动,提供连接池

@ -16,7 +16,7 @@
这些特性每一个都不简单, **Datav 就是为了解决这些问题而生**
> Datav 不是全世界最好的可观测性和数据可视化平台,这毫无疑问,至少目前不是。但是它对开发者最友好,并且支持丰富的可编程性的平台
> Datav 不是全世界最好的可观测性和数据可视化平台,这毫无疑问,至少目前不是。但是它对开发者最友好,并且支持丰富的可编程性的平台
>
> 当一个产品它的代码结构清晰简洁、架构干净、使用的技术符合时代主流、文档齐全,当一个产品在各种使用细节上都为开发者专门设计过,当一个产品允许各种深度可定制时,我们可以称其开发者友好

@ -65,6 +65,10 @@
width: 5px;
height: 5px;
}
::-webkit-scrollbar-thumb {
background: #99ccff;
border-radius: 3px;
}
/* 表格靠左对齐 */
table {

Loading…
Cancel
Save