2022-07-22
2022-07-22 本文已影响0人
wwmin_
1. rust 闭包
三种 Fn 的关系
实际上,一个闭包并不仅仅实现某一种 Fn
特征,规则如下:
- 所有的闭包都自动实现了
FnOnce
特征,因此任何一个闭包都至少可以被调用一次 - 没有移出所捕获变量的所有权的闭包自动实现了
FnMut
特征 - 不需要对捕获变量进行改变的闭包自动实现了
Fn
特征
fn main() {
let s = String::new();
let update_string = || println!("{}",s);
exec(update_string);
exec1(update_string);
exec2(update_string);
}
fn exec<F: FnOnce()>(f: F) {
f()
}
fn exec1<F: FnMut()>(mut f: F) {
f()
}
fn exec2<F: Fn()>(f: F) {
f()
}
2. 迭代器
数组实现了 IntoIterator 特征,Rust 通过 for 语法糖,自动把实现了该特征的数组类型转换为迭代器(你也可以为自己的集合类型实现此特征),最终让我们可以直接对一个数组进行迭代.
next 方法对迭代器的遍历是消耗性的,每次消耗它一个元素,最终迭代器中将没有任何元素,只能返回 None。
其实有一个细节,由于 Vec
动态数组实现了 IntoIterator
特征,因此可以通过 into_iter
将其转换为迭代器
- into_iter 会夺走所有权
- iter 是借用
- iter_mut 是可变借用
Iterator 和 IntoIterator 的区别
这两个其实还蛮容易搞混的,但我们只需要记住,Iterator
就是迭代器特征,只有实现了它才能称为迭代器,才能调用 next
。
而 IntoIterator
强调的是某一个类型如果实现了该特征,它可以通过 into_iter
,iter
等方法变成一个迭代器。
#![allow(unused)]
fn main() {
let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
assert_eq!(v2, vec![2, 3, 4]);
}
上面代码中,使用了 collect 方法,该方法就是一个消费者适配器,使用它可以将一个迭代器中的元素收集到指定类型中,这里我们为 v2 标注了 Vec<> 类型,就是为了告诉 collect:请把迭代器中的元素消费掉,然后把值收集成 Vec<> 类型,至于为何使用 _,因为编译器会帮我们自动推导。