1. 闭包的基本使用与特性
闭包定义会为每个参数和返回值类型推导一个具体的类型,但是不能推导两次
闭包能捕捉环境中的变量
//1、闭包是可以保存进变量或者作为参数传递给其它函数的匿名函数。闭包和函数不同的是,闭包允许捕获调用者作用域中的值。
//2、闭包的使用方式
//3、使用带有泛型和Fn trait的闭包 ?
//语法格式
fn add_one_v1(x: u32) -> u32 {
x + 1
}
fn main() {
// 闭包的定义
let use_closure = || {
println!("This is a closure");
};
use_closure();
//闭包定义会为每个参数和返回值类型推导一个具体的类型,但是不能推导两次
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| {x + 1};
let add_one_v4 = |x| x+1;
let a = add_one_v1(5);//use function
let b = add_one_v2(5);
let c = add_one_v3(5);
let d = add_one_v4(5);
println!("a = {}, b = {}, c = {}, d = {}", a, b, c, d);
//不能推导两次的例子
let example_closure = |x| x;
let s = example_closure(String::from("hello"));
println!("s = {}", s);
// let n = example_closure(5); // 这种使用方法会报错, 前面已经推导过一次了.
let n = example_closure(5.to_string());
println!("n = {}", n);
//捕捉环境中的变量
let i = 1;
let exe = |x| -> i32 {
x + i // i环境中的变量
};
let r = exe(5);
println!("r + i = {}", r);
}
2. 使用带有泛型和Fn trait的闭包
// 实现一个缓存,只处理第一次传入的值并保存
// 实现一个缓存,只处理第一次传入的值并保存
// 使用带有泛型和Fn trait的闭包
struct Cacher<T>
where T: Fn(u32) -> u32 // 泛型 特性约束(bound trait)
{
calculation: T,
value: Option<u32>,
}
impl <T> Cacher<T>
where T: Fn(u32) -> u32 // 泛型 特性约束(bound trait)
{
fn new(calculation: T) -> Self { // 定义构造关联函数 Self 等同于 Cacher<T>
Self {
calculation,
value: Option::None,
}
}
fn value(&mut self, arg: u32) -> u32 { //定义结构体方法
match self.value {
Option::Some(v) => {
v
}
Option::None => {
let v = (self.calculation)(arg); // 得到新计算的值
self.value = Option::Some(v); // 赋值给结构体自身
v // 返回
}
}
}
}
fn main() {
let mut c = Cacher::new(|x| -> u32 { x+1 });
let v1 = c.value(1);
println!("v1 = {}", v1);
let v2 = c.value(2);
println!("v2 = {}", v2);
}
// 结果:
// v1 = 2
// v2 = 2
3. 闭包可以通过三种方式捕获其环境
fn main() {
//let x = 4;
//let equal_to_x = |z| z==x;
//let y = 4;
//assert!(equal_to_x(y));
let x = vec![1, 2, 3];
let equal_to_x = move |z| {z==x};
// println!("x === {:?}", x);
let y = vec![1, 2, 3];
assert!(equal_to_x(y));
}
//闭包可以通过三种方式捕获其环境,它们对应函数的三种获取参数的方式,分别是获取所有权、可变借用、不可变借用。
//这三种捕获值的方式被编码为如下三个Fn trait:
//(1)FnOnce消费从周围作用域捕获的变量,闭包周围的作用域被称为其环境。为了消费捕获到的变量,闭包必须获取其所有权并在定义闭包时将其移进闭包。其名称的Once部分代表了闭包不能多次获取相同变量的所有权。
//(2)FnMut获取可变的借用值,所以可以改变其环境。
//(3)Fn从其环境获取不可变的借用值。
//当创建一个闭包时,rust会根据其如何使用环境中的变量来推断我们希望如何引用环境。由于所有闭包都可以被调用至少一次,因此所有闭包都实现了FnOnce。没有移动被捕获变量的所有权到闭包的闭包也实现了FnMut,而不需要对捕获的变量进行可变访问的闭包实现了Fn。
4. 迭代器以及基本特点
use std::iter::Iterator;
// 1, 迭代器负责遍历序列 和 决定序列何时结束的逻辑
// 2, 迭代器是惰性的, 意思就是调用方法使用迭代器之前, 不会有任何效果
// 3, 每个迭代器都实现了 Iterator trait, (在标准库中)
// trait Iterator {
// type Item;
// // next 是唯一要求实现的方法, 结束的时候返回None.
// fn next(self) -> Option<Self::Item>; // type Item 和 Self::Item这种用法叫做定义trait的关联类型
// }
fn main() {
let v1 = vec![1, 2];
let mut v1_iter = v1.iter();
// for val in v1_iter {
// println!("val = {}", val);
// }
if let Some(v) = v1_iter.next() {
println!("v = {}", v);
}
if let Some(v) = v1_iter.next() {
println!("v = {}", v);
}
if let Some(v) = v1_iter.next() {
println!("v = {}", v);
} else {
println!("none");
}
// 迭代可变引用
let mut v2 = vec![1,2,3];
let mut v2_iter = v2.iter_mut();
if let Some(v) = v2_iter.next() {
*v = 3;
}
println!("v2 = {:?}", v2);
//消费适配器
let v3 = vec![1,2,3];
let v3_iter = v3.iter();
let total: i32 = v3_iter.sum(); //调用消费适配器 sum 来求和, 这里不能类型自动推导,需要标注total类型
println!("total = {}", total);
//迭代适配器
let v4 = vec![1, 2, 3];
let v5 : Vec<_> = v4.iter().map(|x| { x + 1 }).collect();
println!("v5 = {:?}", v5);
//过滤
let v6: Vec<_> = v5.into_iter().filter(|x| { *x > 2 }).collect();
println!("v6 = {:?}", v6);
}
//结果:
// v = 1
// v = 2
// none
// v2 = [3, 2, 3]
// total = 6
// v5 = [2, 3, 4]
// v6 = [3, 4]
5. 自定义迭代器
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Self {
Self {
count: 0
}
}
}
//自定义实现迭代器
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> { // type Item 和 Self::Item这种用法叫做定义trait的关联类型
self.count += 1;
if self.count < 6 {
Option::Some(self.count)
} else {
None //1, 迭代器负责遍历序列 和 决定序列何时结束的逻辑
}
}
}
fn main() {
let mut counter = Counter::new();
for i in 0..7 {
if let Option::Some(v) = counter.next() {
println!("i = {}, v = {}", i, v);
} else {
println!("i = {}, at end", i);
break;
}
}
println!("over");
}
// 结果:
// i = 0, v = 1
// i = 1, v = 2
// i = 2, v = 3
// i = 3, v = 4
// i = 4, v = 5
// i = 5, at end
// over
网友评论