下面是上一节 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)
}