速成课第3节-练习解答

下面是上一节 Rust 速成课 “迭代器和错误” 中的练习题的解决方案。

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

练习1

这里的诀窍是用 Skip 数据类型“包裹” Args 数据类型:

use std::env::{args, Args};
use std::iter::Skip;

fn main() {
    let args: Skip<Args> = args().skip(1);
    for arg in args {
        println!("{}", arg);
    }
}

您可能已经注意到,我们不需要将 args 标记为可变的。 这是因为我们将 args 值移动到 for 循环中,这意味着在 main 函数中看不到 for 循环对其进行的任何变更。

练习2

当我们在该示例的上下文中调用 parse 时,类型推断告诉我们,width 和 height 结果必须为 u32,因为它们在 Frame 中用作字段。 Rust 能够根据所需的返回类型决定使用什么实现。 酷!

Haskellers 再次翻白眼并说“老新闻”。

练习3

完整的源文件:

#[derive(Debug)]
struct Frame {
    width: u32,
    height: u32,
}

#[derive(Debug)]
enum ParseError {
    TooFewArgs,
    TooManyArgs,
    InvalidInteger(String),
}

struct ParseArgs(std::env::Args);

impl ParseArgs {
    fn new() -> ParseArgs {
        ParseArgs(std::env::args())
    }


    fn require_arg(&mut self) -> Result<String, ParseError> {
        match self.0.next() {
            None => Err(ParseError::TooFewArgs),
            Some(s) => Ok(s),
        }
    }

    fn require_no_args(&mut self) -> Result<(), ParseError> {
        match self.0.next() {
            Some(_) => Err(ParseError::TooManyArgs),
            None => Ok(()),
        }
    }
}

fn parse_u32(s: String) -> Result<u32, ParseError> {
    match s.parse() {
        Err(_) => Err(ParseError::InvalidInteger(s)),
        Ok(x) => Ok(x),
    }
}

fn parse_args() -> Result<Frame, ParseError> {
    let mut args = ParseArgs::new();

    // skip the command name
    args.require_arg()?;

    let width_str = args.require_arg()?;
    let height_str = args.require_arg()?;
    args.require_no_args()?;
    let width = parse_u32(width_str)?;
    let height = parse_u32(height_str)?;

    Ok(Frame { width, height })
}

fn main() {
    println!("{:?}", parse_args());
}

练习4

我们希望确保宽度和高度的最小尺寸。 首先,让我们在 ParseError 枚举中添加两个变量:

WidthTooSmall(u32),
HeightTooSmall(u32),

然后将下面的代码添加到 parse_args 函数中,就在 Ok 之前:

if width < 2 {
    return Err(WidthTooSmall(width));
}
if height < 2 {
    return Err(HeightTooSmall(height));
}

练习5

这是我们提出尾 ? 的另一个完美时机!

fn main () -> Result<(), self::parse_args::ParseError> {
    let frame = parse_args::parse_args()?;
    let mut game = Game::new(frame);
    let sleep_duration = std::time::Duration::from_millis(33);
    loop {
        println!("{}", game);
        game.step();
        std::thread::sleep(sleep_duration);
    }
}

最后更新于