速成课第5节-练习解答

下面是上一节 Rust 速成课 “ 迭代器和闭包三规则” 中练习题的解决方案。

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

练习1

fn double(x: &mut u32) {
    *x *= 2;
}

fn main() {
    let mut x = 5;
    double(&mut x);
    println!("{}", x);
}

注意,变量 x 不需要是可变的,因为我们只修改它引用的值。

练习2

(IMO)直截了当的解决办法是:

struct InfiniteUnit;

impl IntoIterator for InfiniteUnit {
    type Item = ();
    type IntoIter = InfiniteUnitIter;

    fn into_iter(self) -> Self::IntoIter {
        InfiniteUnitIter
    }
}

struct InfiniteUnitIter;

impl Iterator for InfiniteUnitIter {
    type Item = ();
    fn next(&mut self) -> Option<()> {
        Some(())
    }
}

fn main() {
    let mut count = 0;
    for _ in InfiniteUnit {
        count += 1;
        println!("count == {}", count);
        if count >= 5 {
            break;
        }
    }
}

但是,如果你想更聪明一点,在标准库中已经有一个函数可以创建一个无限迭代器,叫做 repeat。 使用它,您可以绕过这里的额外结构:

struct InfiniteUnit;

impl IntoIterator for InfiniteUnit {
    type Item = ();
    type IntoIter = std::iter::Repeat<()>;

    fn into_iter(self) -> Self::IntoIter {
        std::iter::repeat(())
    }
}

fn main() {
    let mut count = 0;
    for _ in InfiniteUnit {
        count += 1;
        println!("count == {}", count);
        if count >= 5 {
            break;
        }
    }
}

练习3

闭包版本:

fn main() {
    let msg: &str = "Hi!";
    let say_hi = |msg| println!("{}", msg);
    say_hi(msg);
    say_hi(msg);
}

函数版本:

fn main() {
    let msg: &str = "Hi!";
    fn say_hi(msg: &str) {
        println!("{}", msg);
    }
    say_hi(msg);
    say_hi(msg);
}

因为 say_hi 不引用局部作用域中的任何变量,所以它不需要是闭包。

练习4

fn main() {
    call_with_hi(say_message);
    call_with_hi(say_message);
}

fn say_message(msg: &str) {
    println!("{}", msg);
}

fn call_with_hi<F>(f: F)
    where F: Fn(&str)
{
    f("Hi!");
}

练习5

我们得到的第一个错误消息是:

rror[E0599]: no method named `map` found for type `std::vec::Vec<u32>` in the current scope
 --> main.rs:5:23
  |
5 |         for i in nums.map(unimplemented!()) {
  |                       ^^^
  |
  = note: the method `map` exists but the following trait bounds were not satisfied:
          `&mut std::vec::Vec<u32> : std::iter::Iterator`
          `&mut [u32] : std::iter::Iterator`

看来我们需要一个迭代器了。 我们有三种不同的选择: into_iter()、 iter() 和 iter_mut ()。 由于我们需要多次使用结果,并且不需要任何变异,iter() 似乎是正确的选择。 一旦我们用 nums.iter () 替换nums.iter().map,我们可以进入 unimplemented!() 位。

我们需要一个数字翻倍的结局。 这很简单: | x | x * 2。 把这个放进去就行了! 额外的挑战: 闭包是 FnOnce,FnMut,还是 Fn?

练习6

您需要在 create 调用上添加一个 .unwrap()调用:

use std::io::Write;
let mut file = std::fs::File::create("mylog.txt").unwrap();
file.write_all(b"I was clicked.\n");

这样,您将收到来自编译器的警告,告知您已忽略来自 write_all 的 Result。 这是不好的做法,编译器理应会向您大喊大叫。 您可以使用unwrap() 修复该问题。 但是,这也是一种不好的做法:)。

练习7

extern crate gtk;

use gtk::prelude::*;

use gtk::{Button, Window, WindowType};

use std::cell::RefCell;
use std::io::Write;

fn main() -> Result<(), Box<std::error::Error>> {
    gtk::init()?;

    let window = Window::new(WindowType::Toplevel);
    window.set_title("First GTK+ Program");
    window.set_default_size(350, 70);
    let button = Button::new_with_label("Click me!");
    window.add(&button);
    window.show_all();

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    let file = std::fs::File::create("mylog.txt")?;
    let file = RefCell::new(file);
    button.connect_clicked(move |_| {
        match file.borrow_mut().write_all(b"I was clicked.\n") {
            Ok(()) => (),
            Err(e) => eprintln!("Error writing to file: {}", e),
        }
    });

    gtk::main();

    Ok(())
}

最后更新于