当前位置: 首页 > news >正文

Rust- 闭包

A closure in Rust is an anonymous function you can save in a variable or pass as an argument to another function. You can create the closure using a lightweight syntax and access variables from the scope in which it’s defined.

Here’s an example of a closure that increases a number by one:

let plus_one = |x: i32| x + 1;let a = 5;
println!("{}", plus_one(a)); // Outputs 6

In this example, plus_one is a closure that takes one argument x and returns x + 1.

Closures in Rust are similar to lambdas in other languages, but they have some specific behaviors and capabilities.

  • Capture Environment: Closures have the ability to capture values from the scope in which they’re defined. Here’s an example:

    let num = 5;
    let plus_num = |x: i32| x + num;
    println!("{}", plus_num(10)); // Outputs 15
    

    Here, plus_num captures the value of num from the surrounding environment.

  • Flexible Input Types: Unlike functions, closures don’t require you to annotate the types of the input parameters. However, you can if you want to, and sometimes doing so can increase clarity.

  • Three Flavors of Closures: Closures in Rust come in three forms, which differ in how they capture variables from the surrounding scope: Fn, FnMut, and FnOnce. The type is chosen by the compiler based on how the closure uses variables from the environment.

    • FnOnce consumes the variables it captures from its enclosing scope, known as the “once” because it can’t take ownership more than once.
    • FnMut can change the environment because it mutably borrows values.
    • Fn borrows values from the environment immutably.

Let’s start with an overview of each:

  1. FnOnce captures variables and moves them into the closure when it is defined. It can consume those variables when the closure is called. FnOnce closures can’t be called more than once in some contexts without duplication.

  2. FnMut can mutate and also consume variables from the environment in which it is defined.

  3. Fn borrows variables from the environment immutably.

Now, let’s have a look at some examples for each type:

// Example of FnOnce
let x = "hello".to_string();
let consume_x = move || println!("{}", x);
consume_x(); // "hello"
// consume_x(); This won't compile because `x` has been moved into the closure// Example of FnMut
let mut y = "hello".to_string();
let mut append_world = || y.push_str(" world");
append_world();
println!("{}", y); // "hello world"// Example of Fn
let z = "hello".to_string();
let print_z = || println!("{}", z);
print_z();
print_z(); // We can call this as many times as we want.

① In the first example, the closure takes ownership of x (indicated by the move keyword), so it’s a FnOnce.

② In the second example, the closure mutably borrows y, so it’s a FnMut.

③ In the third example, the closure immutably borrows z, so it’s a Fn.

Rust chooses how to capture variables on the fly without any annotation required. The move keyword is used to force the closure to take ownership of the values it uses.

Closures are a fundamental feature for many Rust idioms. They are used extensively in iterator adapters, threading, and many other situations.

fn main() {/*|| 代替 ()将输入参数括起来函数体界定符是{},对于单个表达式是可选的,其他情况必须加上。有能力捕获外部环境的变量。|参数列表| {业务逻辑}|| {业务逻辑}闭包可以赋值一个变量。*/let double = |x| {x * 2};let add = |a, b| {a + b};let x = add(2, 4);println!("{}", x);          // 6let y = double(5);println!("{}", y);          // 10let v = 3;let add2 = |x| {v + x};println!("{}", add2(4));    // 7/*闭包,可以在没有标注的情况下运行。可移动(move), 可借用(borrow), 闭包可以通过引用 &T可变引用 &mut T值 T捕获1. 闭包是一个在函数内创建立即调用的另外一个函数。2. 闭包是一个匿名函数3. 闭包虽然没有函数名,但可以把整个闭包赋值一个变量,通过该变量来完成闭包的调用4. 闭包不用声明返回值,但可以有返回值。并且使用最后一条语句的执行结果作为返回值,闭包的返回值也可以给变量。5. 闭包也称之为内联函数,可以访问外层函数里的变量。*/
}
fn main() {let add = |x, y| x + y;let result = add(3, 4);println!("{}", result); // 7receives_closure(add); // // 闭包作为参数执行结果 => 8let y = 2;receives_closure2(|x| x + y); // closure(1) => 3let y = 3;receives_closure2(|x| x + y); // closure(1) => 4let closure = returns_closure();println!("返回闭包 => {}", closure(1)); // 返回闭包 => 7let result = do1(add, 5);println!("result(1) => {}", result(1)); // result(1) => 6let result = do2(add, 5);println!("result(2) => {}", result(2)); // result(2) => 7
}fn do2<F, X, Y, Z>(f: F, x: X) -> impl Fn(Y) -> Z
whereF: Fn(X, Y) -> Z,X: Copy,
{move |y| f(x, y)
}// 参数和返回值都有闭包
fn do1<F>(f: F, x: i32) -> impl Fn(i32) -> i32
whereF: Fn(i32, i32) -> i32,
{move |y| f(x, y)
}// 返回闭包
fn returns_closure() -> impl Fn(i32) -> i32 {|x| x + 6
}// 闭包作为参数
fn receives_closure<F>(closure: F)
whereF: Fn(i32, i32) -> i32,
{let result = closure(3, 5);println!("闭包作为参数执行结果 => {}", result)
}// 闭包捕获变量
fn receives_closure2<F>(closure: F)
whereF: Fn(i32) -> i32,
{let result = closure(1);println!("closure(1) => {}", result);
}
http://www.lryc.cn/news/102820.html

相关文章:

  • 【数据挖掘torch】 基于LSTM电力系统负荷预测分析(Python代码实现)
  • 「JVM」性能调优工具
  • IDEA Debug小技巧 添加减少所查看变量、查看不同线程
  • 基于SpringBoot+Vue的车辆充电桩管理系统设计与实现(源码+LW+部署文档等)
  • Bean的加载方式
  • 《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(13)-Fiddler请求和响应断点调试
  • Android 13(T) - Media框架(1)- 总览
  • 简述vue3(ts)+antdesignvue项目框架搭建基本步骤
  • webpack : 无法加载文件 C:\Program Files\nodejs\webpack.ps1
  • GDAL OGR C++ API 学习之路 (5)OGRLayer篇 代码示例
  • NIDEC COMPONENTS尼得科科宝滑动型DIP开关各系列介绍
  • 一起学算法(滑动窗口篇)
  • HTML <q> 标签
  • 机器学习02-再识K邻近算法(自定义数据集训练及测试)
  • github使用笔记及git协作常用命令
  • iOS - Apple开发者账户添加新测试设备
  • vue 前端 邮箱、密码、手机号码等输入验证规则
  • 如何看待前端已死这个问题(大学生篇)
  • 揭开高级产品经理思维的秘密
  • Java 学习路线图
  • 在springboot项目中使用策略工厂模式
  • mysql综合练习语法总结
  • 统计神经网络参数量、MAC、FLOPs等信息
  • 【多模态】21、BARON | 通过引入大量 regions 来提升模型开放词汇目标检测能力(CVPR2021)
  • Ansible 自动化运维
  • 指纹浏览器能为TikTok运营提供哪些便利?
  • 关于远程直接内存访问技术 RDMA 的高性能架构设计介绍 | 龙蜥技术
  • 【Boost搜索引擎项目】
  • JVM入门篇-JVM的概念与学习路线
  • “程序员求职攻略:IT技术岗面试的必备技巧“