> For the complete documentation index, see [llms.txt](https://chapin666.gitbook.io/rust-crash-course-zh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://chapin666.gitbook.io/rust-crash-course-zh/4.-crates-he-geng-duo-de-die-dai-qi/su-cheng-ban-di-4-ke-lian-xi-jie-da.md).

# 速成课第4节-练习解答

下面是上一节 Rust 速成课 “Crates,  I/O 和更多迭代器” 中的练习题的解答。

这篇文章是基于 [FP](https://www.fpcomplete.com/rust) 完成 Rust 教学系列的一部分。 如果你在博客之外阅读这篇文章，你可以在[介绍文章的顶部](https://www.snoyman.com/blog/2018/10/introducing-rust-crash-course)找到这个系列中所有文章的链接。 也可[订阅 RSS](https://www.snoyman.com/feed/rust-crash-course) 频道。

## 练习1

你可以在 [Github Gist ](https://gist.github.com/snoyberg/936ecefd7b6fabc2438e51f02bfe36cb)找到我的完整解决方案。 如果你的解决方案看起来和我的有点不同，不要担心。 另外，看看你能从我的实现中学到什么有趣的东西，或者你想对它做一些改进。

## 练习2

```rust
struct TheAnswer;

impl Iterator for TheAnswer {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        Some(42)
    }
}
```

## 练习3

让我们从简单的解决方案开始：

```rust
struct Fibs {
    x: u32,
    y: u32,
}

fn fibs() -> Fibs {
    Fibs {
        x: 0,
        y: 1,
    }
}

impl Iterator for Fibs {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        let orig_x = self.x;
        let orig_y = self.y;

        self.x = orig_y;
        self.y = orig_x + orig_y;

        Some(orig_x)
    }
}

fn main() {
    for i in fibs().take(10) {
        println!("{}", i);
    }
}
```

然而，如果你把 take (10)提高到 take (47) ，你的输出结果看起来会是：

```rust
701408733
1134903170
thread 'main' panicked at 'attempt to add with overflow', foo.rs:21:18
note: Run with `RUST_BACKTRACE=1` for a backtrace.
```

一种解决方法是用 u64，但这只是在延迟问题。 相反，我们可以使用Rust的checked\_add：

```rust
fn next(&mut self) -> Option<u32> {
    let orig_x = self.x;
    let orig_y = self.y;

    match orig_x.checked_add(orig_y) {
        // overflow
        None => None,

        // no overflow
        Some(new_y) => {
            self.x = orig_y;
            self.y = new_y;

            Some(orig_x)
        }
    }
}
```

现在，一旦发生溢出，我们的流将停止。

如果您想在这里真正进步，您实际上可以再输出两个值。 为此，我们需要分配一个取消引用的值，并使用一个枚举来跟踪我们的状态：

```rust
fn next(&mut self) -> Option<u32> {
    use Fibs::*;
    match *self {
        Done => None,
        OneLeft(x) => {
            *self = Done;
            Some(x)
        }
        Running(orig_x, orig_y) => {
            *self = match orig_x.checked_add(orig_y) {
                // overflow
                None => OneLeft(orig_y),
                Some(new_y) => Running(orig_y, new_y),
            };

            Some(orig_x)
        }
    }
}
```

## 练习4

```rust
impl<I> Iterator for Doubler<I>
    where
    I: Iterator,
    I::Item: std::ops::Add<Output=I::Item> + Copy,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            None => None,
            Some(x) => Some(x + x),
        }
    }
}
```

## 练习5

Fold 方法有两个参数: 初始值 和 一个用于将运行总数与下一个值相加的函数。 使用闭包的一种方法是：

```rust
fn main() {
    let res = (1..11).fold(0, |x, y| x + y);
    println!("{}", res);
}
```

另一种方法是直接引用加法函数。 还记得 \* 操作符有一个 Mul 特性吗？ 还有一个添加特性：

```rust
fn main() {
    let res = (1..11).fold(0, std::ops::Add::add);
    println!("{}", res);
}
```

至于编写自己的求和函数：我们将最终回到通用的情况，并且必须提供适当的特征。 我们将使用类似的方法，分别使用From和u8：

```rust
fn sum<I>(iter: I) -> I::Item
    where
    I: Iterator,
    I::Item: std::ops::Add<Output=I::Item> + From<u8>,
{
    iter.fold(From::from(0u8), std::ops::Add::add)
}
```
