📔
rust-crash-course-zh
  • 目录
  • 0. Rust速成课介绍
  • 1. 小试牛刀
    • 速成课第1节
    • 速成课第1节-练习解答
  • 2. 所有权基础
    • 速成课第2节
    • 速成课第2节-练习解答
  • 3. 迭代器与错误
    • 速成课第3节
    • 速成课第3节-练习解答
  • 4. Crates和更多的迭代器
    • 速成课第4节
    • 速成课第4节-练习解答
  • 5. 参数、迭代器和闭包三法则
    • 速成课第5节
    • 速成课第5节-练习解答
  • 6. 生命周期和切片
    • 速成课第6节
    • 速成课第6节-练习解答
  • 7. Async,Futures和Tokio
  • 8. 直接了当的Future
  • 9. Tokio 0.2
由 GitBook 提供支持
在本页
  • 练习1
  • 练习2
  • 练习3
  • 练习4
  • 练习5

这有帮助吗?

  1. 4. Crates和更多的迭代器

速成课第4节-练习解答

上一页速成课第4节下一页5. 参数、迭代器和闭包三法则

最后更新于4年前

这有帮助吗?

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

这篇文章是基于 完成 Rust 教学系列的一部分。 如果你在博客之外阅读这篇文章,你可以在找到这个系列中所有文章的链接。 也可 频道。

练习1

你可以在 找到我的完整解决方案。 如果你的解决方案看起来和我的有点不同,不要担心。 另外,看看你能从我的实现中学到什么有趣的东西,或者你想对它做一些改进。

练习2

struct TheAnswer;

impl Iterator for TheAnswer {
    type Item = u32;

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

练习3

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

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) ,你的输出结果看起来会是:

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:

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

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

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

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

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 方法有两个参数: 初始值 和 一个用于将运行总数与下一个值相加的函数。 使用闭包的一种方法是:

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

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

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

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

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)
}
FP
介绍文章的顶部
订阅 RSS
Github Gist