1 闭包

1.1 闭包与局部函数

  1. fn main(){
  2. // 不能这样定义匿名函数
  3. // let t = fn(t:i32,x:&i32) -> i32 { t + *x };
  4. // 这样(嵌套地)定义局部函数是合法的
  5. fn t(t:i32,x: &i32) -> i32 { t + *x };
  6. assert_eq!(vec![1,2,3].iter().fold(0,t),6);
  7. // 但通常使用更简洁的闭包: 通常不指定闭包参数和返回值的类型,而使用自动类型推导
  8. // 而对于函数,不能省略参数和返回值类型
  9. assert_eq!(vec![1,2,3].iter().fold(0,|a,x| a + x),6);
  10. }

1.2 闭包可以捕获环境中的变量

  1. fn main() {
  2. let x = 4;
  3. // 闭包可以使用环境中的变量 x
  4. let equal_to_x = |z| z == x;
  5. // 不合法: 函数不能使用环境中的变量 x,函数中 x 没有定义
  6. //fn equal_to_x2(z : i32) -> bool { z == x }
  7. let y = 4;
  8. assert!(equal_to_x(y));
  9. }

1.3 闭包捕获环境的方式

  • 闭包有三种可能的环境捕获方式:
    1. Fn:以不可变引用的方式使用环境中的变量
    2. FnMut:以可变引用的方式使用环境中的变量
    3. FnOnce:将获取环境中变量的所有权,无法在闭包之外使用被捕获的变量,也无法多次调用闭包
  • 编译器自动分析代码,采用合适的方式进行环境捕获
  • 可以在闭包前用move明确指示,将使用到的变量的所有权移动到闭包中,通常用在启动线程的时候
  1. fn main() {
  2. let t = String::from("abc");
  3. //闭包捕获了环境中的变量t,因为String类型的加运算要求所有权,所以闭包的类型是FnOnce: t的所有权被移动到闭包中
  4. let d = ||println!("{}",t + "def");
  5. //println!("{}",t);// 这里无法使用所有权被移动的变量t
  6. d();
  7. //d();// FnOnce类型的闭包不能被两次调用:变量t只能被移动一次到闭包中
  8. //println!("{}",t);// 这里无法使用所有权被移动的变量t
  9. }

2 迭代器

2.1 迭代器特性Iterator

  1. trait Iterator {
  2. type Item;
  3. fn next(&mut self) -> Option<Self::Item>;
  4. }
  • 实现迭代器特性的时候,仅需要实现一个方法: next
  • 迭代器的其他方法都有默认实现
  • 注意:返回值是Option类型

    2.2 集合类型的迭代器

  • std::collections模块中的集合类型通常实现了三个与迭代器相关的方法

    1. iter():返回一个迭代器,每个元素是集合元素的引用
    2. iter_mut():返回一个迭代器,每个元素是集合元素的可变引用
    3. into_iter():转移所有权,将自身变成一个迭代器,每个元素是集合元素本身(所有权类型)
  1. fn main() {
  2. let v1 = vec![1, 2, 3];
  3. {
  4. let mut v1_iter = v1.iter();
  5. assert_eq!(v1_iter.next(), Some(&1));// 元素是引用类型
  6. assert_eq!(v1_iter.next(), Some(&2));
  7. assert_eq!(v1_iter.next(), Some(&3));
  8. assert_eq!(v1_iter.next(), None);
  9. }
  10. // 注意: 大括号是必须的,如果没有前面的大括号,则仍然有效的v1_iter是对v1的借用
  11. // 下面的 v1.into_iter() 就无法转移 v1 的所有权了
  12. let mut v1_iter = v1.into_iter();
  13. assert_eq!(v1_iter.next(), Some(1));// 元素是所有权类型
  14. assert_eq!(v1_iter.next(), Some(2));
  15. assert_eq!(v1_iter.next(), Some(3));
  16. assert_eq!(v1_iter.next(), None);
  17. }

2.2.1 消费适配器

  • Iterator特性的各种调用next()方法的方法称作消费适配器(consuming adaptors)
  • 常见的消费适配器有:minmaxlastsum

2.2.2 迭代器适配器

  • Iterator特性的一些返回一个新迭代器的方法,称作迭代器适配器(iterator adaptors)
  • 常见的迭代器适配器有:takeskiprevcycle