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