# 速成课第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)
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET 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?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
