Merge pull request #414 from AllanDowney/patch-1

Update: unified format
pull/417/head
孙飞Sunface 3 years ago committed by GitHub
commit ebf50279ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,7 +12,7 @@ fn main() {
}
```
上面的代码展示了非常简单的闭包 `sum`,它拥有一个入参 `y`,同时捕获了作用域中的 `x` 的值,因此调用 `sum(2)` 意味着将 2(参数 `y`) 跟 1`x`)进行相加,最终返回它们的和:`3`。
上面的代码展示了非常简单的闭包 `sum`,它拥有一个入参 `y`,同时捕获了作用域中的 `x` 的值,因此调用 `sum(2)` 意味着将 2(参数 `y`跟 1`x`)进行相加,最终返回它们的和:`3`。
可以看到 `sum` 非常符合闭包的定义:可以赋值给变量,允许捕获调用者作用域中的值。
@ -41,8 +41,7 @@ fn workout(intensity: u32, random_number: u32) {
"旁边有妹子在看俯卧撑太low再来 {} 组卧推!",
muuuuu(intensity)
);
} else {
if random_number == 3 {
} else if random_number == 3 {
println!("昨天练过度了,今天还是休息下吧!");
} else {
println!(
@ -51,7 +50,6 @@ fn workout(intensity: u32, random_number: u32) {
);
}
}
}
fn main() {
// 强度
@ -64,11 +62,21 @@ fn main() {
}
```
可以看到,在健身时我们根据想要的强度来调整具体的动作,然后调用 `muuuuu` 函数来开始健身。这个程序本身很简单,没啥好说的,但是假如未来不用 `muuuu` 函数了,是不是得把所有 `muuuu` 都替换成,比如说 `woooo` ?如果 `muuuu` 出现了几十次,那意味着我们要修改几十处地方。
可以看到,在健身时我们根据想要的强度来调整具体的动作,然后调用 `muuuuu` 函数来开始健身。这个程序本身很简单,没啥好说的,但是假如未来不用 `muuuuu` 函数了,是不是得把所有 `muuuuu` 都替换成,比如说 `woooo` ?如果 `muuuuu` 出现了几十次,那意味着我们要修改几十处地方。
#### 函数变量实现
一个可行的办法是,把函数赋值给一个变量,然后通过变量调用:
```rust
use std::thread;
use std::time::Duration;
// 开始健身好累我得发出声音muuuu...
fn muuuuu(intensity: u32) -> u32 {
println!("muuuu.....");
thread::sleep(Duration::from_secs(2));
intensity
}
fn workout(intensity: u32, random_number: u32) {
let action = muuuuu;
if intensity < 25 {
@ -80,8 +88,7 @@ fn workout(intensity: u32, random_number: u32) {
"旁边有妹子在看俯卧撑太low, 再来 {} 组卧推!",
action(intensity)
);
} else {
if random_number == 3 {
} else if random_number == 3 {
println!("昨天练过度了,今天还是休息下吧!");
} else {
println!(
@ -90,6 +97,15 @@ fn workout(intensity: u32, random_number: u32) {
);
}
}
fn main() {
// 强度
let intensity = 10;
// 随机值用来决定某个选择
let random_number = 7;
// 开始健身
workout(intensity, random_number);
}
```
@ -104,6 +120,9 @@ fn workout(intensity: u32, random_number: u32) {
上面提到 `intensity` 要是变化怎么办,简单,使用闭包来捕获它,这是我们的拿手好戏:
```rust
use std::thread;
use std::time::Duration;
fn workout(intensity: u32, random_number: u32) {
let action = || {
println!("muuuu.....");
@ -120,8 +139,7 @@ fn workout(intensity: u32, random_number: u32) {
"旁边有妹子在看俯卧撑太low再来 {} 组卧推!",
action()
);
} else {
if random_number == 3 {
} else if random_number == 3 {
println!("昨天练过度了,今天还是休息下吧!");
} else {
println!(
@ -130,7 +148,6 @@ fn workout(intensity: u32, random_number: u32) {
);
}
}
}
fn main() {
// 动作次数
@ -274,7 +291,7 @@ where
## 捕获作用域中的值
在之前代码中,我们一直在用闭包的匿名函数特性(赋值给变量),然而闭包还拥有一项函数所不具备的特性:捕获作用域中的值。
在之前代码中,我们一直在用闭包的匿名函数特性(赋值给变量),然而闭包还拥有一项函数所不具备的特性:捕获作用域中的值。
```rust
fn main() {
let x = 4;

@ -1,6 +1,7 @@
# 函数式编程
罗马不是一天建成的编程语言亦是如此每一门编程语言在借鉴前辈的同时也会提出自己独有的特性Rust 即是如此。当站在巨人肩膀上时,一个人所能看到的就更高更远,恰好,我们看到了函数式语言的优秀特性,例如:
- 使用函数作为参数进行传递
- 使用函数作为函数返回值
- 将函数赋值给变量
@ -8,6 +9,7 @@
见猎心喜,我们忍不住就借鉴了过来,于是你能看到本章的内容,天下语言一大。。。跑题了。
关于函数式编程到底是什么的争论由来已久,本章节并不会踏足这个泥潭,因此我们在这里主要关注的是函数式特性:
- 闭包closure
- 迭代器iterator
- 模式匹配

@ -26,7 +26,7 @@ for v in arr {
那又有同学要发问了,在 Rust 中数组是迭代器吗?因为在之前的代码中直接对数组 `arr` 进行了迭代,答案是 `No`。那既然数组不是迭代器,为啥咱可以对它的元素进行迭代呢?
简而言之就是数组实现了 `IntoIterator` 特征Rust 通过 `for` 语法糖,自动把实现了该特征的数组类型转换为迭代器(你也可以为自己的集合类型实现此特征),最终让我们可以直接对一个数组进行迭代,类似的还有:
简而言之就是数组实现了 `IntoIterator` 特征Rust 通过 `for` 语法糖,自动把实现了该特征的数组类型转换为迭代器(你也可以为自己的集合类型实现此特征),最终让我们可以直接对一个数组进行迭代,类似的还有:
```rust
for i in 1..10 {
println!("{}", i);
@ -95,7 +95,7 @@ fn main() {
- `next` 方法返回的是 `Option` 类型,当有值时返回 `Some(i32)`,无值时返回 `None`
- 遍历是按照迭代器中元素的排列顺序依次进行的,因此我们严格按照数组中元素的顺序取出了 `Some(1)``Some(2)``Some(3)`
- 手动迭代必须将迭代器声明为 `mut` 可变,因为调用 `next` 会改变迭代器其中的状态数据(当前遍历的位置等),而 `for` 循环去迭代则无需标注 `mut`,因为它会帮我们自动完成
- 手动迭代必须将迭代器声明为 `mut` 可变,因为调用 `next` 会改变迭代器其中的状态数据(当前遍历的位置等),而 `for` 循环去迭代则无需标注 `mut`,因为它会帮我们自动完成
总之,`next` 方法对**迭代器的遍历是消耗性的**,每次消耗它一个元素,最终迭代器中将没有任何元素,只能返回 `None`
@ -305,7 +305,7 @@ fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
`filter` 是迭代器适配器,用于对迭代器中的每个值进行过滤。 它使用闭包作为参数,该闭包的参数 `s` 是来自迭代器中的值,然后使用 `s` 跟外部环境中的 `shoe_size` 进行比较,若相等,则在迭代器中保留 `s` 值,若不相等,则从迭代器中剔除 `s` 值,最终通过 `collect` 收集为 `Vec<Shoe>` 类型。
## 实现 Iterator 特征
之前的内容我们一直基于数组来创建迭代器,实际上,不仅仅是数组,基于其它集合类型一样可以创建迭代器,例如 `HashMap`。 你也可以创建自己的迭代器 - 只要为自定义类型实现 `Iterator` 特征即可。
之前的内容我们一直基于数组来创建迭代器,实际上,不仅仅是数组,基于其它集合类型一样可以创建迭代器,例如 `HashMap`。 你也可以创建自己的迭代器 —— 只要为自定义类型实现 `Iterator` 特征即可。
首先,创建一个计数器:
```rust
@ -464,14 +464,12 @@ test bench::bench_iter ... bench: 983,858 ns/iter (+/- 44,673)
迭代器是 Rust 的 **零成本抽象**zero-cost abstractions之一意味着抽象并不会引入运行时开销这与 `Bjarne Stroustrup`C++ 的设计和实现者)在 `Foundations of C++2012` 中所定义的 **零开销**zero-overhead如出一辙
```
In general, C++ implementations obey the zero-overhead principle: What you dont use, you dont pay for.
And further: What you do use, you couldnt hand code any better.
一般来说C++的实现遵循零开销原则:没有使用时,你不必为其买单。
更进一步说,需要使用时,你也无法写出更优的代码了。
(翻译一下:用就完事了)
```
> In general, C++ implementations obey the zero-overhead principle: What you dont use, you dont pay for.
> And further: What you do use, you couldnt hand code any better.
>
> 一般来说C++的实现遵循零开销原则:没有使用时,你不必为其买单。
> 更进一步说,需要使用时,你也无法写出更优的代码了。
> (翻译一下:用就完事了)
总之,迭代器是 Rust 受函数式语言启发而提供的高级语言特性可以写出更加简洁、逻辑清晰的代码。编译器还可以通过循环展开Unrolling、向量化、消除边界检查等优化手段使得迭代器和 `for` 循环都有极为高效的执行效率。

Loading…
Cancel
Save