前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入浅出理解Rust闭包

深入浅出理解Rust闭包

作者头像
草帽lufei
发布2024-07-20 11:25:33
880
发布2024-07-20 11:25:33
举报
文章被收录于专栏:程序语言交流

闭包基本语法

代码语言:javascript
复制
|参数1, 参数2, ...| -> 返回类型 {
    // 闭包体
}

闭包主要特点

参数列表

  • 用竖线 | 包裹
  • 可以省略类型,由编译器推断
  • 如果没有参数,可以写成 ||

返回类型

  • 通常可以省略,由编译器推断
  • 如果需要明确指定,使用 -> 后跟类型

闭包体

  • 如果只有一个表达式,可以省略花括号 {}
  • 多个语句需要用花括号包围

闭包的特性和使用场景

捕获环境变量

闭包可以捕获其定义环境中的变量

使用场景
  • 当需要在函数内部创建一个使用局部变量的函数时
  • 在异步编程中,将上下文传递给未来执行的代码
代码语言:javascript
复制
let factor = 2;
let multiply = |x| x * factor;

灵活的类型推断

闭包参数和返回值的类型通常可以被编译器自动推断

使用场景
  • 编写简洁的代码,特别是函数式编程风格中
  • 使用迭代器方法,如 map, filter
代码语言:javascript
复制
let numbers = vec![1, 2, 3, 4, 5];
let squares: Vec<i32> = numbers.iter().map(|x| x * x).collect();
println!("{:?}", squares);

作为函数参数

闭包可以作为函数的参数传递

使用场景
  • 实现回调函数
  • 自定义排序或过滤逻辑
代码语言:javascript
复制
fn apply_operation<F>(x: i32, f: F) -> i32
where
    F: Fn(i32) -> i32,
{
    f(x)
}

let double = |x| x * 2;
println!("结果:{}", apply_operation(5, double));

实现 FnFnMutFnOnce trait

根据如何捕获和使用环境变量,闭包会自动实现这些 trait

使用场景
  • Fn: 多次调用,不能修改捕获的变量
  • FnMut: 多次调用,可能修改捕获的变量
  • FnOnce:只能调用一次,可能消耗捕获的变量
代码语言:javascript
复制
let mut count = 0;
let mut increment = || {
    count += 1;
    println!("计数: {}", count);
};

increment();
increment();

延迟执行

闭包定义代码块,但不立即执行

使用场景
  • 惰性求值
  • 定义可重用的操作
代码语言:javascript
复制
let expensive_calculation = |x| {
    println!("复杂计算...");
    x * x * x
};

let result = expensive_calculation(4);
println!("结果:{:?}", result);

场景小结

闭包在Rust中非常强大和灵活,特别适用于:

  • 函数式编程
  • 自定义迭代器操作
  • 异步编程
  • 事件处理和回调
  • 延迟计算
  • 性能优化

Rust闭包设计目标

Rust中闭包的设计目标是要快:比函数指针还要快,快到甚至可以在对性能敏感的热点代码中使用它们

在大多数语言中,闭包会在堆中分配内存、进行动态派发以及进行垃圾回收。因此,创建、调用和收集每一个闭包都会花费一点点额外的 CPU 时间。更糟的是,闭包往往难以内联,而内联是编译器用来消除函数调用开销并实施大量其他优化的关键技术。总而言之,闭包在这些语言中确实慢到值得手动将它们从节奏紧凑的内层循环中去掉

Rust 闭包则没有这些性能缺陷。它们没有垃圾回收。与 Rust 中的其他所有类型一样,除非你将闭包放在 BoxVec 或其他容器中,否则它们不会被分配到堆上。由于每个闭包都有不同的类型,因此 Rust 编译器只要知道正在调用的闭包的类型,就可以内联该闭包的代码

Rust 的“激进赌注”是基于“必然存在好的替代设计”这个假设的。有时你可以通过让每个闭包接受它需要的引用作为参数,来解决闭包所有权和生命周期的问题。有时你可以为系统中的每个事物分配一个编号,并传递这些编号而不是传递引用。或者你可以实现 MVC 的众多变体之一,其中的对象并非都相互引用。或者将工具包建模为具有单向数据流的非 MVC 系统,比如 Facebook 的 Flux 架构

合理使用闭包,每个人都可以写出更简洁优雅的代码

欢迎大家讨论交流,如果喜欢本文章或感觉文章有用,动动你那发财的小手点赞、收藏、关注再走呗 ^_^ 掘金社区:草帽lufei

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 草帽Lufei 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 闭包基本语法
  • 闭包主要特点
    • 参数列表
      • 返回类型
        • 闭包体
        • 闭包的特性和使用场景
          • 捕获环境变量
            • 使用场景
          • 灵活的类型推断
            • 使用场景
          • 作为函数参数
            • 使用场景
          • 实现 Fn、FnMut 或 FnOnce trait
            • 使用场景
          • 延迟执行
            • 使用场景
          • 场景小结
          • Rust闭包设计目标
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档