做民宿最大的网站,音速企业名录搜索软件,服装定制合同范本,城市建设服务中心网站闭包 Closure
闭包是一种匿名函数#xff0c;它可以赋值给变量也可以作为参数传递给其它函数#xff0c;不同于函数的是#xff0c;它允许捕获调用者作用域中的值#xff0c;例如#xff1a;
fn main() {let x 1;let sum |y| x y;assert_eq!(3, sum(2));
}上面的代码…闭包 Closure
闭包是一种匿名函数它可以赋值给变量也可以作为参数传递给其它函数不同于函数的是它允许捕获调用者作用域中的值例如
fn main() {let x 1;let sum |y| x y;assert_eq!(3, sum(2));
}上面的代码展示了非常简单的闭包 sum它拥有一个入参 y同时捕获了作用域中的 x 的值因此调用 sum(2) 意味着将 2参数 y跟 1x进行相加,最终返回它们的和3。
可以看到 sum 非常符合闭包的定义可以赋值给变量允许捕获调用者作用域中的值。
Rust 闭包在形式上借鉴了 Smalltalk 和 Ruby 语言与函数最大的不同就是它的参数是通过 |parm1| 的形式进行声明如果是多个参数就 |param1, param2,...| 下面给出闭包的形式定义
|param1, param2,...| {语句1;语句2;返回表达式
}如果只有一个返回表达式的话定义可以简化为
|param1| 返回表达式下面展示了同一个功能的函数和闭包实现形式
fn add_one_v1 (x: u32) - u32 { x 1 }
let add_one_v2 |x: u32| - u32 { x 1 };
let add_one_v3 |x| { x 1 };
let add_one_v4 |x| x 1 ;注意闭包中最后一行表达式返回的值就是闭包执行后的返回值。
迭代器 Iterator
迭代器允许我们迭代一个连续的集合例如数组、动态数组 Vec、HashMap 等在此过程中只需关心集合中的元素如何处理而无需关心如何开始、如何结束、按照什么样的索引去访问等问题。
IntoIterator 特征拥有一个 into_iter 方法因此我们还可以显式的把数组转换成迭代器
let arr [1, 2, 3];
for v in arr.into_iter() {println!({}, v);
}迭代器之所以成为迭代器就是因为实现了 Iterator 特征要实现该特征最主要的就是实现其中的 next 方法该方法控制如何从集合中取值最终返回值的类型是关联类型 Item。
例子模拟实现 for 循环
因为 for 循环是迭代器的语法糖因此我们完全可以通过迭代器来模拟实现它
let values vec![1, 2, 3];{let result match IntoIterator::into_iter(values) {mut iter loop {match iter.next() {Some(x) { println!({}, x); },None break,}},};result
}IntoIterator::into_iter 是使用完全限定的方式去调用 into_iter 方法这种调用方式跟 values.into_iter() 是等价的。
同时我们使用了 loop 循环配合 next 方法来遍历迭代器中的元素当迭代器返回 None 时跳出循环。
可以使用 into_iter 的方式将数组转化为迭代器除此之外还有 iter 和 iter_mut它们的区别如下
into_iter 会夺走所有权iter 是借用iter_mut 是可变借用
Iterator 和 IntoIterator 的区别
这两个其实还蛮容易搞混的但我们只需要记住Iterator 就是迭代器特征只有实现了它才能称为迭代器才能调用 next。
而 IntoIterator 强调的是某一个类型如果实现了该特征它可以通过 into_iteriter 等方法变成一个迭代器。
使用 collect 收集成 HashMap 集合
use std::collections::HashMap;
fn main() {let names [sunface, sunfei];let ages [18, 18];let folks: HashMap_, _ names.into_iter().zip(ages.into_iter()).collect();println!({:?},folks);
}zip 是一个迭代器适配器它的作用就是将两个迭代器的内容压缩到一起形成 IteratorItem(ValueFromA, ValueFromB) 这样的新的迭代器在此处就是形如 [(name1, age1), (name2, age2)] 的迭代器。
然后再通过 collect 将新迭代器中(K, V) 形式的值收集成 HashMapK, V同样的这里必须显式声明类型然后 HashMap 内部的 KV 类型可以交给编译器去推导最终编译器会推导出 HashMapstr, i32完全正确
闭包作为适配器参数
之前的 map 方法中我们使用闭包来作为迭代器适配器的参数它最大的好处不仅在于可以就地实现迭代器中元素的处理还在于可以捕获环境值
struct Shoe {size: u32,style: String,
}fn shoes_in_size(shoes: VecShoe, shoe_size: u32) - VecShoe {shoes.into_iter().filter(|s| s.size shoe_size).collect()
}filter 是迭代器适配器用于对迭代器中的每个值进行过滤。 它使用闭包作为参数该闭包的参数 s 是来自迭代器中的值然后使用 s 跟外部环境中的 shoe_size 进行比较若相等则在迭代器中保留 s 值若不相等则从迭代器中剔除 s 值最终通过 collect 收集为 VecShoe 类型。
实现 Iterator 特征
之前的内容我们一直基于数组来创建迭代器实际上不仅仅是数组基于其它集合类型一样可以创建迭代器例如 HashMap。 你也可以创建自己的迭代器 —— 只要为自定义类型实现 Iterator 特征即可。
首先创建一个计数器
struct Counter {count: u32,
}impl Counter {fn new() - Counter {Counter { count: 0 }}
}我们为计数器 Counter 实现了一个关联函数 new用于创建新的计数器实例。下面我们继续为计数器实现 Iterator 特征
impl Iterator for Counter {type Item u32;fn next(mut self) - OptionSelf::Item {if self.count 5 {self.count 1;Some(self.count)} else {None}}
}首先将该特征的关联类型设置为 u32由于我们的计数器保存的 count 字段就是 u32 类型 因此在 next 方法中最后返回的是实际上是 Optionu32 类型。
每次调用 next 方法都会让计数器的值加一然后返回最新的计数值一旦计数大于 5就返回 None。
最后使用我们新建的 Counter 进行迭代 let mut counter Counter::new();assert_eq!(counter.next(), Some(1));
assert_eq!(counter.next(), Some(2));
assert_eq!(counter.next(), Some(3));
assert_eq!(counter.next(), Some(4));
assert_eq!(counter.next(), Some(5));
assert_eq!(counter.next(), None);实现 Iterator 特征的其它方法
可以看出实现自己的迭代器非常简单但是 Iterator 特征中不仅仅是只有 next 一个方法那为什么我们只需要实现它呢因为其它方法都具有默认实现所以无需像 next 这样手动去实现而且这些默认实现的方法其实都是基于 next 方法实现的。
下面的代码演示了部分方法的使用
let sum: u32 Counter::new().zip(Counter::new().skip(1)).map(|(a, b)| a * b).filter(|x| x % 3 0).sum();
assert_eq!(18, sum);其中 zipmapfilter 是迭代器适配器
zip 把两个迭代器合并成一个迭代器新迭代器中每个元素都是一个元组由之前两个迭代器的元素组成。例如将形如 [1, 2, 3, 4, 5] 和 [2, 3, 4, 5] 的迭代器合并后新的迭代器形如 [(1, 2),(2, 3),(3, 4),(4, 5)]map 是将迭代器中的值经过映射后转换成新的值[2, 6, 12, 20]filter 对迭代器中的元素进行过滤若闭包返回 true 则保留元素[6, 12]反之剔除
而 sum 是消费者适配器对迭代器中的所有元素求和最终返回一个 u32 值 18。