update readme

pull/89/head
sunface 3 years ago
parent ea642e7839
commit 04e89c5f32

@ -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. 读一本好书: [<<Rust编程指南>>](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. 读一本好书: [<<Rust编程指南>>](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`这种章节目录形式

@ -8,3 +8,6 @@ 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}"
[output.html.fold]
enable = true

@ -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)

@ -0,0 +1 @@
# 对抗编译检查

@ -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<T> {
data: *const T, // *const是可变的
len: usize,
cap: usize,
}
```
和之前的例子不同,这个定义已经满足我们的各种要求了。`Vec`的每一个泛型参数都被至少一个成员使用过了。非常完美!
你高兴的太早了。
Drop检查器会判断`Vec<T>`并不拥有T类型的值然后它认为无需担心Vec在析构函数里能不能安全地销毁T再然后它会允许人们创建不安全的Vec析构函数。
为了让drop检查器知道我们确实拥有T类型的值也就是需要在销毁Vec的时候同时销毁T我们需要添加一个额外的PhantomData
``` Rust
use std::marker:
struct Vec<T> {
data: *const T, // *const是可变的
len: usize,
cap: usize,
_marker: marker::PhantomData<T>,
}
```
让裸指针拥有数据是一个很普遍的设计,以至于标准库为它自己创造了一个叫`Unique<T>`的组件,它可以:
- 封装一个`*const T`处理变性
- 包含一个PhantomData<T>
- 自动实现`Send`/`Sync`模拟和包含T时一样的行为
- 将指针标记为`NonZero`以便空指针优化
## `PhantomData`模式表
下表展示了各种牛X闪闪的`PhantomData`用法:
| Phantom 类型 | `'a` | `'T` |
|----|----|----|
|`PhantomData<T>`|-|协变可触发drop检查|
|`PhantomData<&'a T>`|协变|协变|
|`PhantomData<&'a mut T>`|协变|不变|
|`PhantomData<*const T>`|-|协变|
|`PhantomData<*mut T>`|-|不变|
|`PhantomData<fn(T)>`|-|逆变(*)|
|`PhantomData<fn() -> T>`|-|协变|
|`PhantomData<fn(T) -> T>`|-|不变|
|`PhantomData<Cell<&'a ()>>`|不变|-|
(*)如果发生变性的冲突,这个是不变的

@ -0,0 +1 @@
# 大师之路

@ -11,3 +11,5 @@ 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)
7. [Rust in action](https://livebook.manning.com/book/rust-in-action/chapter-5/)

@ -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<T> {
a: T,
}
struct Bar;
impl<T> Maker for Bar
where T: Default {
type Item = Foo<T>;
fn make(&mut self) -> Foo<T> {
Foo {
a: <T as Default>::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<T> Maker for Bar
```
可以使用[幽灵数据]()来初步解决
```rust
use std::marker::PhantomData;
struct Bar<T> {
_m: PhantomData<T>
}
impl<T> Maker for Bar<T>
where T: Default {
type Item = Foo<T>;
fn make(&mut self) -> Foo<T> {
Foo {
a: <T as Default>::default(),
}
}
}
```
关于这个问题,主要是因为在`impl`代码块中,关联类型是由`Self`和所有输入类型参数一同决定的,也就是说`关联类型`中出现的泛型参数,必须在`impl`中有所定义,要么为`Maker`增加泛型变量,要么为`Bar`增加。
如果你想要让Self拥有多种可能的类型就得使用外部输入的类型参数而不是关联类型
```rust
use std::default::Default;
trait Maker<Item> {
fn make(&mut self) -> Item;
}
struct Foo<T> {
a: T,
}
struct Bar;
impl<T> Maker<Foo<T>> for Bar
where T: Default
{
fn make(&mut self) -> Foo<T> {
Foo {
a: <T as Default>::default(),
}
}
}
```
类似的例子还有这个https://www.reddit.com/r/rust/comments/r61l29/generic_impl_doesnt_work_while_generic_function/

@ -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/

@ -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<SomeValue, SomeError> {
Ok("foo".into())
}
fn bar(input: &str) -> Result<SomeOtherValue, SomeError> {
if input == "bar" {
Ok("Success".into())
} else {
Err("This is a failure message".into())
}
}
fn my_fun() -> Result<SomeOtherValue, SomeError> {
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);
}
```
Loading…
Cancel
Save