Skip to content

Commit 94bb4b1

Browse files
Merge pull request #300 from arrowrowe/enhance/first-reformat
排版规范尝试
2 parents f2926a3 + 729335c commit 94bb4b1

44 files changed

Lines changed: 420 additions & 334 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.editorconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*]
7+
end_of_line = lf
8+
insert_final_newline = true
9+
10+
[*.{md,markdown}]
11+
trim_trailing_whitespace = true

.gitignore

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,41 @@
1-
_book/
1+
# Built files
2+
_book/
3+
4+
# Node-related ignoring, copied from https://github.com/github/gitignore/blob/master/Node.gitignore
5+
# Logs
6+
logs
7+
*.log
8+
npm-debug.log*
9+
10+
# Runtime data
11+
pids
12+
*.pid
13+
*.seed
14+
15+
# Directory for instrumented libs generated by jscoverage/JSCover
16+
lib-cov
17+
18+
# Coverage directory used by tools like istanbul
19+
coverage
20+
21+
# nyc test coverage
22+
.nyc_output
23+
24+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
25+
.grunt
26+
27+
# node-waf configuration
28+
.lock-wscript
29+
30+
# Compiled binary addons (http://nodejs.org/api/addons.html)
31+
build/Release
32+
33+
# Dependency directories
34+
node_modules
35+
jspm_packages
36+
37+
# Optional npm cache directory
38+
.npm
39+
40+
# Optional REPL history
41+
.node_repl_history

.textlintrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"editorconfig": true
4+
}
5+
}

1st-glance/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Rust 是一门系统级编程语言,被设计为保证内存和线程安全,并防止段错误。作为系统级编程语言,它的基本理念是 “零开销抽象”。理论上来说,它的速度与 C / C++ 同级。
22

3-
Rust 可以被归为通用的、多范式、编译型的编程语言,类似 C 或者 C++。与这两门编程语言不同的是,Rust 是线程安全的
3+
Rust 可以被归为通用的、多范式、编译型的编程语言,类似 C 或者 C++。与这两门编程语言不同的是,Rust 是线程安全的!
44

55
Rust 编程语言的目标是,创建一个高度安全和并发的软件系统。它强调安全性、并发和内存控制。尽管 Rust 借用了 C 和 C++ 的语法,它不允许空指针和悬挂指针,二者是 C 和 C++ 中系统崩溃、内存泄露和不安全代码的根源。
66

@@ -44,13 +44,13 @@ Rust 运行在以下操作系统上:Linux, OS X, Windows, FreeBSD, Android, iO
4444
- stormgbs
4545
- tennix
4646
- anzhihun
47-
- zonyitoo(Elton,e猫)
47+
- zonyitooElton, e猫)
4848
- 42
4949
- [Naupio(N猫)](https://github.com/Naupio)
5050
- F001(失落的神喵)
5151
- wangyu190810
5252
- domty
53-
- [MarisaKirisame(帅气可爱的魔理沙)](https://github.com/MarisaKirisame)
53+
- [MarisaKirisame帅气可爱的魔理沙](https://github.com/MarisaKirisame)
5454
- [Knight42](https://github.com/knight42)
5555

5656
等。在此,向他们的辛苦工作和无私奉献表示尊敬和感谢!

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ wiki: https://wiki.rust-china.org/
7777
* [模式匹配](match/overview.md)「wayslog」
7878
* [match关键字](match/match.md)
7979
* [模式](match/pattern.md)
80-
* [Trait (特征)](trait/overview.md)「JohnSmithX」
80+
* [Trait(特征)](trait/overview.md)「JohnSmithX」
8181
* [trait关键字](trait/trait.md)
8282
* [trait对象](trait/trait-object.md)
8383
* [泛型](generics/generics.md)「stormgbs」
@@ -129,8 +129,8 @@ wiki: https://wiki.rust-china.org/
129129
* [编译器参数](attr-and-compiler-args/rustc-options.md)
130130
* [Cargo参数配置](cargo-detailed-cfg/cargo-detailed-cfg.md)「fuyingfuying」
131131
* [测试与评测](testing/preface.md)「daogangtang」
132-
* [测试 (testing/threearchtest.md)
133-
* [评测 (testing/bench.md)
132+
* [测试](testing/threearchtest.md)
133+
* [评测](testing/bench.md)
134134
* [代码风格](coding-style/style.md)「tiansiyuan」
135135
* [Any与反射](any/any.md)「wayslog」
136136
* [安全(safe)](safe/safe.md)「daogangtang」
@@ -142,9 +142,9 @@ wiki: https://wiki.rust-china.org/
142142
* [链表](data-structure/linked_list.md)
143143
* [图结构](data-structure/graph.md)
144144
* [标准库介绍](std/overview.md)「wayslog」
145-
* [系统命令:调用grep](std/process.md)
146-
* [目录操作:简单grep](std/fs-and-path.md)
147-
* [网络模块:W回音](std/net.md)
145+
* [系统命令调用grep](std/process.md)
146+
* [目录操作简单grep](std/fs-and-path.md)
147+
* [网络模块W回音](std/net.md)
148148
* [实战篇](action/preface.md)「wangyu190810」
149149
* [实战:Json处理](action/json_data/readme.md)
150150
* [实战:Web 应用开发入门](action/mysite/readme.md)
@@ -154,15 +154,15 @@ wiki: https://wiki.rust-china.org/
154154

155155
本书使用 `CC BY-SA 3.0` 协议,转载请注明地址。
156156

157-
## gitbook生成
157+
## GitBook 生成
158158

159159
直接用:
160160

161161
```
162162
gitbook serve
163163
```
164164

165-
即可
165+
即可
166166

167167

168168
## 成为Contributors
@@ -172,4 +172,4 @@ gitbook serve
172172
## ChangeLog
173173

174174
1. 2016年3月31日,初稿完成。发布 v1.0 版。
175-
2. 2016年5月2日,完成1.1.0版本
175+
2. 2016年5月2日,完成 1.1.0 版本

action/db/readme.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ postgres="*"
2525

2626
当然我们还是进行最简单的操作,直接粘贴复制,[代码来源](https://github.com/sfackler/rust-postgres#overview)
2727

28-
``` rust
28+
``` rust
2929

3030
extern crate postgres;
3131

@@ -108,10 +108,10 @@ pub fn insert_info(conn : &Connection,title : &str, body: &str){
108108
let stmt = match conn.prepare("insert into blog (title, body) values ($1, $2)") {
109109
Ok(stmt) => stmt,
110110
Err(e) => {
111-
println!("Preparing query failed: {:?}", e);
111+
println!("Preparing query failed: {:?}", e);
112112
return;
113-
}
114-
};
113+
}
114+
};
115115
stmt.execute(&[&title, &body]).expect("Inserting blogposts failed");
116116
}
117117

@@ -126,9 +126,9 @@ pub fn query<T>(conn: &Connection,query: &str) ->PgResult<T>
126126
//rows.iter().next().unwrap()
127127
row.get_opt(2).unwrap()
128128

129-
}
129+
}
130130

131-
pub fn query_all(conn: &Connection,query: &str){
131+
pub fn query_all(conn: &Connection,query: &str){
132132
println!("Executing query: {}", query);
133133
for row in &conn.query(query,&[]).unwrap(){
134134
let person = Person{
@@ -139,7 +139,7 @@ pub fn query_all(conn: &Connection,query: &str){
139139
println!("Found person {}", person.name);
140140
}
141141

142-
}
142+
}
143143

144144
```
145145
然后在main.rs 中调用相应的函数代码如下
@@ -150,7 +150,7 @@ pub fn query_all(conn: &Connection,query: &str){
150150

151151
``` rust
152152
extern crate postgres;
153-
extern crate db;
153+
extern crate db;
154154

155155
use postgres::{Connection, SslMode};
156156

@@ -162,19 +162,19 @@ struct Blog {
162162
}
163163

164164
fn main() {
165-
let conn:Connection=connect();
166-
165+
let conn:Connection=connect();
166+
167167
let blog = Blog{
168168
title: String::from("title"),
169169
body: String::from("body"),
170-
};
170+
};
171171
let title = blog.title.to_string();
172172
let body = blog.body.to_string();
173-
insert_info(&conn,&title,&body);
173+
insert_info(&conn,&title,&body);
174174

175175
for row in query::<String>(&conn,"select * from blog"){
176176
println!("{:?}",row);
177-
}
177+
}
178178
let sql = "select * from person";
179179
query_all(&conn,&sql);
180180
}
@@ -192,14 +192,14 @@ fn main() {
192192
说返回的是一个可迭代的数据,那也就是说,我可以使用for循环,将数据打印,
193193
但是发现怎么也不能实现:
194194

195-
``` rust
195+
``` rust
196196

197-
pub fn query_all(conn: &Connection,query: &str){
197+
pub fn query_all(conn: &Connection,query: &str){
198198
println!("Executing query: {}", query);
199-
for row in &conn.query(query,&[]).unwrap(){
199+
for row in &conn.query(query,&[]).unwrap(){
200200
println!("Found person {:?}", row.get_opt(1));
201201
}
202-
}
202+
}
203203

204204
```
205205
报错如下:

coding-style/style.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ let diameter = 7;
149149
/// # 参数
150150
///
151151
/// * `argc` 和 `argv` - 参数向量。在 Unix 系统上,该信息被`os::args`使用。
152-
///
152+
///
153153
/// * `main` - 运行在 M:N 调度器池内的初始过程。
154154
/// 一旦这个过程退出,调度池将开始关闭。
155155
/// 整个池(和这个函数)将只有在所有子线程完成执行后。

concurrency-parallel-threads/message-passing.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ receive 1
3737
3. 通道的发送者和接收者支持N:1,1:N, N:N模式吗?
3838
4. 通道能发送任何数据吗?
3939
5. 发送后的数据,在线程中继续使用没有问题吗?
40-
40+
4141
让我们带着这些问题和思考进入下一个小节,那里有相关的答案。
4242

4343
### 消息类型
@@ -81,23 +81,23 @@ note: `alloc::rc::Rc<Student>` cannot be sent between threads safely
8181
```
8282
看来并不是所有类型的消息都可以通过通道发送,消息类型必须实现`marker trait Send`。Rust之所以这样强制要求,主要是为了解决并发安全的问题,再一次强调,**安全**是Rust考虑的重中之重。如果一个类型是`Send`,则表明它可以在线程间安全的转移所有权(`ownership`),当所有权从一个线程转移到另一个线程后,同一时间就只会存在一个线程能访问它,这样就避免了数据竞争,从而做到线程安全。`ownership`的强大又一次显示出来了。通过这种做法,在编译时即可要求所有的代码必须满足这一约定,这种方式方法值得借鉴,`trait`也是非常强大。
8383

84-
看起来问题得到了完美的解决,然而由于`Send`本身是一个不安全的`marker trait`,并没有实际的`API`,所以实现它很简单,但没有强制保障,就只能靠开发者自己约束,否则还是可能引发并发安全问题。对于这一点,也不必太过担心,因为Rust中已经存在的类,都已经实现了`Send``!Send`,我们只要使用就行。`Send`是一个默认应用到所有Rust已存在类的trait,所以我们用`!Send`显式标明该类没有实现`Send`。目前几乎所有的原始类型都是`Send`,例如前面例子中发送的`i32`。对于开发者而言,我们可能会更关心哪些是非`Send`,也就是实现了`!Send`,因为这会导致线程不安全。更全面的信息参见[`Send`官网API](https://doc.rust-lang.org/std/marker/trait.Send.html)
84+
看起来问题得到了完美的解决,然而由于`Send`本身是一个不安全的`marker trait`,并没有实际的`API`,所以实现它很简单,但没有强制保障,就只能靠开发者自己约束,否则还是可能引发并发安全问题。对于这一点,也不必太过担心,因为Rust中已经存在的类,都已经实现了`Send``!Send`,我们只要使用就行。`Send`是一个默认应用到所有Rust已存在类的trait,所以我们用`!Send`显式标明该类没有实现`Send`。目前几乎所有的原始类型都是`Send`,例如前面例子中发送的`i32`。对于开发者而言,我们可能会更关心哪些是非`Send`,也就是实现了`!Send`,因为这会导致线程不安全。更全面的信息参见[`Send`官网API](https://doc.rust-lang.org/std/marker/trait.Send.html)
8585

8686
对于不是`Send`的情况(`!Send`),大致分为两类:
8787

8888
1. 原始指针,包括`*mut T`和`*const T`,因为不同线程通过指针都可以访问数据,从而可能引发线程安全问题。
8989
2. `Rc`和`Weak`也不是,因为引用计数会被共享,但是并没有做并发控制。
9090

9191
虽然有这些`!Send`的情况,但是逃不过编译器的火眼金睛,只要你错误地使用了消息类型,编译器都会给出类似于上面的错误提示。我们要担心的不是这些,因为错误更容易出现在新创建的自定义类,有下面两点需要注意:
92-
92+
9393
1. 如果自定义类的所有字段都是`Send`,那么这个自定义类也是`Send`。
9494
反之,如果有一个字段是`!Send`,那么这个自定义类也是`!Send`。
9595
如果类的字段存在递归包含的情况,按照该原则以此类推来推论类是`Send`还是`!Send`。
96-
96+
9797
2. 在为一个自定义类实现`Send`或者`!Send`时,必须确保符合它的约定。
9898

9999
到此,消息类型的相关知识已经介绍完了,说了这么久,也该让大家自己练习一下了:请实现一个自定义类,该类包含一个Rc字段,让这个类变成可以在通道中发送的消息类型。
100-
100+
101101
### 异步通道(Channel)
102102
在粗略地尝试通道之后,是时候更深入一下了。Rust的标准库其实提供了两种类型的通道:异步通道和同步通道。上面的例子都是使用的异步通道,为此这一小节我们优先进一步介绍异步通道,后续再介绍同步通道。异步通道指的是:不管接收者是否正在接收消息,消息发送者在发送消息时都不会阻塞。为了验证这一点,我们尝试多增加一个线程来发送消息:
103103

@@ -145,11 +145,11 @@ receive 2
145145
1. 通道是可以同时支持多个发送者的,通过`clone`的方式来实现。
146146
这类似于`Rc`的共享机制,其实从`Channel`所在的库名`std::sync::mpsc`也可以知道这点,因为`mpsc`就是多生产者单消费者(Multiple Producers Single Consumer)的简写。
147147
可以有多个发送者,但只能有一个接收者,即支持的N:1模式。
148-
148+
149149
2. 异步通道具备消息缓存的功能,因为1和2是在没有接收之前就发了的,在此之后还能接收到这两个消息。
150-
150+
151151
那么通道到底能缓存多少消息?在理论上是无穷的,尝试一下便知:
152-
152+
153153
```rust
154154
use std::sync::mpsc;
155155
use std::thread;
@@ -173,7 +173,7 @@ fn main() {
173173
return;
174174
},
175175
}
176-
}
176+
}
177177
});
178178

179179
// 在主线程中接收子线程发送的消息并输出
@@ -184,7 +184,7 @@ fn main() {
184184
最后的结果就是耗费内存为止。
185185

186186
3. 消息发送和接收的顺序是一致的,满足先进先出原则。
187-
187+
188188
上面介绍的内容大多是关于发送者和通道的,下面开始考察一下接收端。通过上面的几个例子,细心一点的可能已经发现接收者的`recv`方法应该会阻塞当前线程,如果不阻塞,在多线程的情况下,发送的消息就不可能接收完全。所以没有发送者发送消息,那么接收者将会一直等待,这一点要谨记。在某些场景下,一直等待是符合实际需求的。但某些情况下并不需一直等待,那么就可以考虑释放通道,只要通道释放了,`recv`方法就会立即返回。
189189

190190
异步通道的具有良好的灵活性和扩展性,针对业务需要,可以灵活地应用于实际项目中,实在是必备良药!
@@ -229,7 +229,7 @@ after send
229229

230230
1. 同步通道是需要指定缓存的消息个数的,但需要注意的是,最小可以是0,表示没有缓存。
231231
2. 发送者是会被阻塞的。当通道的缓存队列不能再缓存消息时,发送者发送消息时,就会被阻塞。
232-
232+
233233
对照上面两点和运行结果来分析,由于主线程在接收消息前先睡眠了,从而子线程这个时候会被调度执行发送消息,由于通道能缓存的消息为0,而这个时候接收者还没有接收,所以`tx.send(1).unwrap()`就会阻塞子线程,直到主线程接收消息,即执行`println!("receive {}", rx.recv().unwrap());`。运行结果印证了这点,要是没阻塞,那么在`before send`之后就应该是`after send`了。
234234

235235
相比较而言,异步通道更没有责任感一些,因为消息发送者一股脑的只管发送,不管接收者是否能快速处理。这样就可能出现通道里面缓存大量的消息得不到处理,从而占用大量的内存,最终导致内存耗尽。而同步通道则能避免这种问题,把接受者的压力能传递到发送者,从而一直传递下去。

concurrency-parallel-threads/parallel.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ fn main() {
1818

1919
colors.par_iter_mut().for_each(|color| {
2020
let c : f32 = if *color < 0.0 {
21-
0.0
21+
0.0
2222
} else if *color > 255.0 {
23-
255.0
24-
} else {
25-
*color
23+
255.0
24+
} else {
25+
*color
2626
};
2727
*color = c / 255.0;
28-
});
28+
});
2929
println!("transformed: {:?}", &colors);
3030
}
3131
```

concurrency-parallel-threads/share-memory.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ use std::sync::Arc;
6969
fn main() {
7070
let var : Arc<i32> = Arc::new(5);
7171
let share_var = var.clone();
72-
72+
7373
// 创建一个新线程
7474
let new_thread = thread::spawn(move|| {
7575
println!("share value in new thread: {}, address: {:p}", share_var, &*share_var);
@@ -105,7 +105,7 @@ pub fn new(data: T) -> Arc<T> {
105105

106106
1. 资源何时释放?
107107
2. 线程如何安全的并发修改和读取?
108-
108+
109109
由于上面两个问题的存在,这就是为什么我们不能直接用`Box`变量在线程中共享的原因,可以看出来,共享内存比消息传递机制似乎要复杂许多。Rust用了引用计数的方式来解决第一个问题,在标准库中提供了两个包裹类,除了上面一个用于多线程的`std::sync::Arc`之外,还有一个不能用于多线程的`std::rc::Rc`。在使用时,可以根据需要进行选择。如果你一不小心把`std::rc::Rc`用于多线程中,编译器会毫不客气地纠正你的。
110110

111111
关于上面的第二个问题,Rust语言及标准库提供了一系列的同步手段来解决。下面的章节我们将详细讲解这些方式和用法。

0 commit comments

Comments
 (0)