美文网首页
闭包与迭代器

闭包与迭代器

作者: 简书网abc | 来源:发表于2021-08-29 15:27 被阅读0次

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

相关文章

  • 闭包与迭代器

    1. 闭包的基本使用与特性 闭包定义会为每个参数和返回值类型推导一个具体的类型,但是不能推导两次闭包能捕捉环境中的...

  • Lua语言学习教程

    lua闭包 函数尾调用 迭代器

  • 5、迭代器实现

    闭包实现迭代器 迭代函数实现迭代器 --1,调用迭代函数,(把状态变量和控制变量当做参数传递给迭代函数) 状态变...

  • python 迭代器 闭包

    迭代器 迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,...

  • python 迭代器 闭包

    迭代器 迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,...

  • python——迭代器,闭包

    迭代器 可迭代对象 可以用for循环的数据类型 判断是否可迭代 生成器一定是迭代器,可用next()的也可以迭代。...

  • python 迭代器 闭包

    迭代器 迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,...

  • 跟诸子学游戏 Lua基础

    1:使用闭包创建迭代器 2:泛型for保存状态变量和控制变量,将状态变量传入迭代器,进行迭代,这个属于无状态迭代器...

  • 15.迭代器、生成器、装饰器

    一、实验目的 迭代器 生成器 生成器表达式 闭包 装饰器 二、知识要点 1.迭代器 迭代是Python最强大的功能...

  • python基础回顾【二】

    11:迭代器: 12:lamdba表达式: 13:内置函数: 14:闭包: 15:装饰器 16:模块

网友评论

      本文标题:闭包与迭代器

      本文链接:https://www.haomeiwen.com/subject/ojwwiltx.html