diff --git a/README.md b/README.md index 47689578..681d47d8 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,74 @@ -# The Way To Rust(Rust编程指南) -入门容易,精通难,成为大师难上难。Rust语言从入门到精通,中间有很多困难需要克服,本书的目标就是帮你跨过这些大山,7天上山写项目,21天下山杀四方. +# Rust编程指南 -## 使用本书你可以 -1. 覆盖从入门到精通所需的所有知识 -2. 桌头工具书,可以随时检索查阅 -3. 提供场景化模版代码,大幅减少复制粘贴成本 +做任何事情,初心和目标很重要,过程也很重要,那么这里我们就来谈谈这些,关于书,关于Rust在国内的发展。 ## Rust学习路线 -0. 入一个社区: [Rust CN Members](https://rust.cm) -1. 读一本好书: [<>](https://mastery.rs) -2. 做一些习题: [Rust Excersise](https://github.com/rustcm/rustex) -3. 看一个项目: [Simple Redis](https://github.com/rustcm/simple-redis) -4. 学常用算法: [Algorithms](https://github.com/rustcm/algorithms) -5. 找优秀开源: [Awesome Rust](https://github.com/rustcm/awesome-rust) +0. 入一个社区: [Rust编程学院](#Rust社区) +1. 读一本好书: [<>](https://wayto.rs) +2. 做一些习题: [Rust Excersise](https://github.com/rustcollege/rustex) +3. 看一个项目: [Simple Redis](https://github.com/rustcollege/simple-redis) +4. 学常用算法: [Algorithms](https://github.com/rustcollege/algorithms) +5. 找优秀开源: [Awesome Rust](https://github.com/rustcollege/awesome-rust) -## 我们的愿景 -愿景:不是少数人的Rust,而是大家的Rust。 +## 关于本书 -Rust语言目前在世界范围已经发展的如火如荼,但是在国内还是非常小众,终其原因是因为我们缺少一整套学习生态:现有的Rust资料几乎没有用中文书写的,就算有,也往往不成体系。 +- 官方书名: Rust编程指南(The Way To Rust) +- 官方网址: https://wayto.rs +- 修订时间: **尚未发行** +- Rust版本:Rust edition 2021 -我们想做的就是跟大家一起打造一个真正的中国Rust社区,同时辅以完整的Rust进阶体系,帮助中国的程序员快速上手Rust并能在实际项目中进行应用,只有降低了这个门槛,才能真正迎来Rust未来在中国的大爆发。 +#### 书本简介 +`Rust编程指南`是一本涵盖了从入门到精通各个阶段的Rust书籍,书本的章节和内容组织经过深思熟虑的设计,以符合中国用户的编程使用习惯,目的是尽量对新手更友好,同时也更方便老手的后期检索查询。 -这个目标任重而道远,欢迎有志之士的加入,QQ群:933696593 +使用Rust的用户往往都对性能非常感兴趣,因此本书对于性能优化方面也是分散落入各个章节中,同时还有一个专门的**性能优化**专题,来帮助用户系统的认识如何优化Rust项目的性能。 -## 版本修订 -本书每半年会修订一次,保证书籍的内容会跟上最新的Rust内容 +针对不同的使用场景,我们也给出了多种模版代码,方便用户直接复制粘贴到代码中,例如读取文件、http请求等,无需再去网上搜索。 +Rust的外部库层次不齐,针对这一点,我们根据功能分类推荐了相应的高质量开源库,同时提供了基础的使用帮助。 + +**在学完这本书后,你也会随之完成数个小型项目**,例如其中一些是: + +- Mandelbrot集合渲染 +- 类Grep命令 +- CPU模拟器 +- 小型数据库 +- 小型Redis +- HTTP等网络请求客户端 +- 小型操作系统内核 + +从上面的列表可以看出,学完本书,不仅会教会你Rust语言,还能学到系统编程和底层编程, 尽情享受奇妙的编程之旅吧。 + +#### 创作初心 + +还有很多,就不一一列举,等待大家自己去探索挖掘。 总之在写作过程中我们始终铭记初心:**为用户打造一本真正的Rust中文好书。 新手用来入门,老手用来提高,高手能用来提升生产力**。 + +#### 目标读者 + +目标读者大致能落在以下三个范畴内 +1. 有其它语言编程基础,无Rust编程语言经验的爱好者 +2. 已经熟悉Rust想要更进一步的中级Rust程序员 +3. 想要随时检索一些Rust知识和代码,对生产力有要求的Rust开发者 + +## Rust社区 + +与国外的Rust发展如火如荼相比,国内的近况不是特别理想。 + +导致目前这种状况的原因,我个人认为有以下几点原因: +1. 上手难度大,学习曲线陡峭 +2. 中文资料少,英文资料难学(基于原因1) +3. 没有体系化的学习路线,新人往往扫完一遍入门书籍,就不知道何去何从 + +因此我联合几个朋友一起创建了Rust编程学院(Rust College), 致力于给国内提供最新、最高质量Rust学习内容。 + +官网网址: +- https://college.cn +- https://rustcollege.cn + + +## Philosophy + +书本的内容组织上遵循以下原则: +1. 内聚性: 每个章节都应该系统的阐述一整块儿独立的内容,尽量减少章节之间的耦合性 +2. 先易后难:按照初级 -> 中级 -> 高级排列内容 +3. 知识链:知识B的学习如果需要先学习知识A,则A一定在B之前出现 +4. 章节命名:当用户突然想了解某个知识点时,可以很快的定位到它所在的章节,例如想了解Arc,就应该`多线程 -> Arc`这种章节目录形式 \ No newline at end of file diff --git a/book.toml b/book.toml index 125ee2eb..214e0ef3 100644 --- a/book.toml +++ b/book.toml @@ -7,4 +7,7 @@ title = "Rust编程指南(The Way To Rust)" additional-css = ["assets/ferris.css", "assets/theme/2018-edition.css"] additional-js = ["assets/ferris.js"] git-repository-url = "https://github.com/rustcm/the-way-to-rust" -edit-url-template = "https://github.com/rustcm/the-way-to-rust/edit/main/{path}" \ No newline at end of file +edit-url-template = "https://github.com/rustcm/the-way-to-rust/edit/main/{path}" + +[output.html.fold] +enable = true \ No newline at end of file diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ddc61851..d53be574 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -46,6 +46,12 @@ - [Bypass Borrow Checker(todo)](advance/bypass-borrow.md) - [常用三方库列表(todo)](advance/utils.md) +## 该内容针对Rust非常高阶的水平,同时无需用专题形式来详述(参考[Rust高级编程](https://learnku.com/docs/nomicon/2018/310-phantom-data/4721?show_current_version=yes)) + +- [大师之路](master/intro.md) + - [对抗编译检查](master/compiler/intro.md) + - [幽灵数据](master/compiler/phantom-data.md) + ## 专题内容 - [难点详解](obscure-concept/intro.md) - [Send、Sync(todo)](obscure-concept/send-sync.md) diff --git a/src/master/compiler/intro.md b/src/master/compiler/intro.md new file mode 100644 index 00000000..e02549bf --- /dev/null +++ b/src/master/compiler/intro.md @@ -0,0 +1 @@ +# 对抗编译检查 diff --git a/src/master/compiler/phantom-data.md b/src/master/compiler/phantom-data.md new file mode 100644 index 00000000..8b14c0cf --- /dev/null +++ b/src/master/compiler/phantom-data.md @@ -0,0 +1,82 @@ +# PhantomData(幽灵数据) + +在编写非安全代码时,我们常常遇见这种情况:类型或生命周期逻辑上与一个结构体关联起来了,但是却不属于结构体的任何一个成员。这种情况对于生命周期尤为常见。比如,`&'a [T]`的`Iter`大概是这么定义的: + +``` Rust +struct Iter<'a, T: 'a> { + ptr: *const T, + end: *const T, +} +``` + +但是,因为`'a`没有在结构体内被使用,它是无界的。由于一些历史原因,无界生命周期和类型禁止出现在结构体定义中。所以我们必须想办法在结构体内用到这些类型,这也是正确的变性检查和drop检查的必要条件。 + +我们使用一个特殊的标志类型`PhantomData`做到这一点。`PhantomData`不消耗存储空间,它只是模拟了某种类型的数据,以方便静态分析。这么做比显式地告诉类型系统你需要的变性更不容易出错,而且还能提供drop检查需要的信息。 + +`Iter`逻辑上包含一系列`&'a T`,所以我们用`PhantomData`这样去模拟它: + +``` Rust +use std::marker; + +struct Iter<'a, T: 'a> { + ptr: *const T, + end: *const T, + _marker: marker::PhantomData<&'a T>, +} +``` + +就是这样,生命周期变得有界了,你的迭代器对于`'a`和`T`也可变了。一切尽如人意。 + +另一个重要的例子是`Vec`,它差不多是这么定义的: + +``` Rust +struct Vec { + data: *const T, // *const是可变的! + len: usize, + cap: usize, +} +``` + +和之前的例子不同,这个定义已经满足我们的各种要求了。`Vec`的每一个泛型参数都被至少一个成员使用过了。非常完美! + +你高兴的太早了。 + +Drop检查器会判断`Vec`并不拥有T类型的值,然后它认为无需担心Vec在析构函数里能不能安全地销毁T,再然后它会允许人们创建不安全的Vec析构函数。 + +为了让drop检查器知道我们确实拥有T类型的值,也就是需要在销毁Vec的时候同时销毁T,我们需要添加一个额外的PhantomData: + +``` Rust +use std::marker: + +struct Vec { + data: *const T, // *const是可变的! + len: usize, + cap: usize, + _marker: marker::PhantomData, +} +``` + +让裸指针拥有数据是一个很普遍的设计,以至于标准库为它自己创造了一个叫`Unique`的组件,它可以: + +- 封装一个`*const T`处理变性 +- 包含一个PhantomData +- 自动实现`Send`/`Sync`,模拟和包含T时一样的行为 +- 将指针标记为`NonZero`以便空指针优化 + +## `PhantomData`模式表 + +下表展示了各种牛X闪闪的`PhantomData`用法: + +| Phantom 类型 | `'a` | `'T` | +|----|----|----| +|`PhantomData`|-|协变(可触发drop检查)| +|`PhantomData<&'a T>`|协变|协变| +|`PhantomData<&'a mut T>`|协变|不变| +|`PhantomData<*const T>`|-|协变| +|`PhantomData<*mut T>`|-|不变| +|`PhantomData`|-|逆变(*)| +|`PhantomData T>`|-|协变| +|`PhantomData T>`|-|不变| +|`PhantomData>`|不变|-| + +(*)如果发生变性的冲突,这个是不变的 \ No newline at end of file diff --git a/src/master/intro.md b/src/master/intro.md new file mode 100644 index 00000000..b0d83fca --- /dev/null +++ b/src/master/intro.md @@ -0,0 +1 @@ +# 大师之路 diff --git a/writing-material/en_books.md b/writing-material/en_books.md index 4429335a..6f592c75 100644 --- a/writing-material/en_books.md +++ b/writing-material/en_books.md @@ -10,4 +10,6 @@ Rust相关英文书籍 5. [Rust异步编程](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) -6. [Rust API Guidlines](https://rust-lang.github.io/api-guidelines/naming.html) \ No newline at end of file +6. [Rust API Guidlines](https://rust-lang.github.io/api-guidelines/naming.html) + +7. [Rust in action](https://livebook.manning.com/book/rust-in-action/chapter-5/) diff --git a/writing-material/posts/fight-with-borrow-check.md b/writing-material/posts/fight-with-compiler-check/borrow.md similarity index 100% rename from writing-material/posts/fight-with-borrow-check.md rename to writing-material/posts/fight-with-compiler-check/borrow.md diff --git a/writing-material/posts/fight-with-compiler-check/generic.md b/writing-material/posts/fight-with-compiler-check/generic.md new file mode 100644 index 00000000..e1181c80 --- /dev/null +++ b/writing-material/posts/fight-with-compiler-check/generic.md @@ -0,0 +1,85 @@ +## the type parameter `T` is not constrained by the impl trait + +```rust +use std::default::Default; + +trait Maker { + type Item; + + fn make(&mut self) -> Self::Item; +} + +struct Foo { + a: T, +} + +struct Bar; + +impl Maker for Bar + where T: Default { + type Item = Foo; + + fn make(&mut self) -> Foo { + Foo { + a: ::default(), + } + } +} +``` + +上面的代码会导致以下编译错误: +```bash +tests/lang.rs:1000:10: 1000:11 error: the type parameter `T` is not constrained by the impl trait, self type, or predicates [E0207] +tests/lang.rs:1000 impl Maker for Bar +``` + +可以使用[幽灵数据]()来初步解决 + +```rust +use std::marker::PhantomData; +struct Bar { + _m: PhantomData +} + +impl Maker for Bar + where T: Default { + type Item = Foo; + + fn make(&mut self) -> Foo { + Foo { + a: ::default(), + } + } +} +``` + +关于这个问题,主要是因为在`impl`代码块中,关联类型是由`Self`和所有输入类型参数一同决定的,也就是说`关联类型`中出现的泛型参数,必须在`impl`中有所定义,要么为`Maker`增加泛型变量,要么为`Bar`增加。 + +如果你想要让Self拥有多种可能的类型,就得使用外部输入的类型参数,而不是关联类型: +```rust +use std::default::Default; + +trait Maker { + fn make(&mut self) -> Item; +} + +struct Foo { + a: T, +} + +struct Bar; + +impl Maker> for Bar + where T: Default +{ + + fn make(&mut self) -> Foo { + Foo { + a: ::default(), + } + } +} +``` + +类似的例子还有这个:https://www.reddit.com/r/rust/comments/r61l29/generic_impl_doesnt_work_while_generic_function/ + diff --git a/writing-material/posts/system_command.md b/writing-material/posts/system_command.md index 16387af7..f483682c 100644 --- a/writing-material/posts/system_command.md +++ b/writing-material/posts/system_command.md @@ -68,4 +68,13 @@ fn main() { ``` +## 调用命令,使用用户的输入作为参数 +```rust +let cmd = Command::new("rev") + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .output()?; +``` + +https://www.reddit.com/r/learnrust/comments/r5wwkz/what_the_relationship_between_processstdio_and/ diff --git a/writing-material/style_guide/coding.md b/writing-material/style_guide/coding.md new file mode 100644 index 00000000..133e3af0 --- /dev/null +++ b/writing-material/style_guide/coding.md @@ -0,0 +1,34 @@ +# 代码风格 + +## 使用[tap](https://github.com/myrrlyn/tap)库来实现`point-free`编程风格 +```rust +use tap::{Tap, TapFallible}; + +type SomeValue = String; +type SomeOtherValue = String; +type SomeError = String; + +fn foo() -> Result { + Ok("foo".into()) +} + +fn bar(input: &str) -> Result { + if input == "bar" { + Ok("Success".into()) + } else { + Err("This is a failure message".into()) + } +} + +fn my_fun() -> Result { + foo() + .tap_err(|err| println!("foo() failed with error: {}", err)) + .and_then(|foo_val| bar(&foo_val)) + .tap(|res| println!("bar() returned result: {:?}", res)) +} + +fn main() { + let result = my_fun(); + println!("{:?}", result); +} +``` \ No newline at end of file