2024 Rust现代实用教程 closures闭包

devtools/2024/11/7 7:19:56/

文章目录

  • 一、闭包基础概念
    • 1.如何使用闭包
  • 二、闭包获取参数byreference与byvalue
    • 1.获取外部参数
    • 2.所有权转移move
  • 三、闭包是怎么工作的
    • 1.闭包在底层是怎么工作的?
    • 2.FnOnce,FnMut,Fn特质
  • 四、闭包类型FnOnce、FnMut和Fn做函数参数的实例
  • 参考

一、闭包基础概念

闭包是一种可以捕获其环境中变量的匿名函数
闭包的语法相对简洁灵活,同时也具有强大的功能。闭包在 Rust 中被广泛用于函数式编程、并发编程以及简化代码等方面。

1.如何使用闭包

定义闭包的语法类似 (但更简单)

  • 在II内定义参数
  • 可选地指定参数/返回类型
  • 在{}内定义闭包体

你可以将闭包分配给一个变量,然后使用该变量,就像它是一个函数名,来调用闭包

Example:

rust">#[derive(Debug)]
struct User {name: String,score: u64,
}// 老派写法
// sort_by_key
// fn sort_score(users: &mut Vec<User>) {
//     users.sort_by_key(sort_helper);
// }// fn sort_helper(u: &User) -> u64 {
//     u.score
// }// 新式写法:直接使用闭包
fn sort_score_closure(users: &mut Vec<User>) {users.sort_by_key(|u| u.score);
}fn main() {let f = |a, b| a + b;println!("{}", f(1.0, 2.0));let a = User {name: "U1".to_owned(),score: 100,};let b = User {name: "U2".to_owned(),score: 80,};let c = User {name: "U3".to_owned(),score: 40,};let d = User {name: "U4".to_owned(),score: 90,};let mut users = vec![a, b, c, d];// sort_score(&mut users);sort_score_closure(&mut users);println!("{:?}", users);
}

编译及运行:

 cargo runCompiling ch29_closure v0.1.0 (/home/wangji/installer/rust/project/ch29_closure)
warning: field `name` is never read--> src/main.rs:3:5|
2 | struct User {|        ---- field in this struct
3 |     name: String,|     ^^^^|= note: `User` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis= note: `#[warn(dead_code)]` on by defaultwarning: `ch29_closure` (bin "ch29_closure") generated 1 warningFinished `dev` profile [unoptimized + debuginfo] target(s) in 12.22sRunning `target/debug/ch29_closure`
3
[User { name: "U3", score: 40 }, User { name: "U2", score: 80 }, User { name: "U4", score: 90 }, User { name: "U1", score: 100 }]

二、闭包获取参数byreference与byvalue

1.获取外部参数

由Rust编译器决定用那种方式获取外部参数
1.不可变引用 Fn
2.可变引用FnMut
3.转移所有权(Move)FnOnce

2.所有权转移move

Rust编译器判断capturesby value

  • 比方说在闭包手动drop该参数

move关键字强制将所有权转移到闭包

Example:

rust">fn main() {// Fn不可变引用获取外部参数let s1 = String::from("1111111111111111111");let s2 = String::from("2222222222222222222");let fn_func = |s| {println!("{s1}");println!("I am {s}");println!("{s1}");};fn_func("yz".to_owned());fn_func("原子".to_owned());println!("{s1} {s2}");// FnMut 可变引用获取外部参数let mut s1 = String::from("1111111111111111111");let mut s2 = String::from("2222222222222222222");let mut fn_func = |s| {s1.push_str("😀");s2.push_str("😀");println!("{s1}");println!("I am {s}");println!("{s1}");};fn_func("yz".to_owned());fn_func("原子".to_owned());println!("{s1} {s2}");// 所有权转移 由编译器根据我们的代码来判读let s1 = String::from("1111");let fn_Once_func = || {println!("{s1}");std::mem::drop(s1); //销毁了};fn_Once_func();// println!("{s1}");// 捕获的参数强制movelet s1 = String::from("1111");let move_fn = move || {println!("{s1}");}; // Fn : FnMut : FnOncemove_fn();// println!("{s1}");let s1 = String::from("1111");std::thread::spawn(move || println!("d  {s1}")); //move确保线程运行的时候,s1还在
}

编译及运行:

 cargo runCompiling ch29_func v0.1.0 (/home/wangji/installer/rust/project/ch29_func)
warning: variable `fn_Once_func` should have a snake case name--> src/main.rs:30:9|
30 |     let fn_Once_func = || {|         ^^^^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `fn_once_func`|= note: `#[warn(non_snake_case)]` on by defaultwarning: `ch29_func` (bin "ch29_func") generated 1 warningFinished `dev` profile [unoptimized + debuginfo] target(s) in 0.35sRunning `target/debug/ch29_func`
1111111111111111111
I am yz
1111111111111111111
1111111111111111111
I am 原子
1111111111111111111
1111111111111111111 2222222222222222222
1111111111111111111😀
I am yz
1111111111111111111😀
1111111111111111111😀😀
I am 原子
1111111111111111111😀😀
1111111111111111111😀😀 2222222222222222222😀😀
1111
1111

三、闭包是怎么工作的

1.闭包在底层是怎么工作的?

1.Rust编译器将闭包放入一个结构体
2.结构体会声明一个cal丨function,而闭包就是函数,cal丨function会包含闭包的所有代码
3.结构体会生产一些属性去捕获闭包外的参数
4.结构体会实现一些特质

  • FnOnce
  • FnMut
  • Fn

2.FnOnce,FnMut,Fn特质

在这里插入图片描述
Fn继承至FnMut,FnMut继承至FnOnce

Example:

rust">fn apply_closure<F: Fn(i32, i32) -> i32>(closure: F, x: i32, y: i32) -> i32 {closure(x, y)
}fn main() {let x = 5;let add_closure = |a, b| {println!("x is: {}", x);a + b + x};let result = apply_closure(add_closure, 5, 6);println!("{}", result);
}

编译及运行:

 cargo runFinished `dev` profile [unoptimized + debuginfo] target(s) in 0.00sRunning `target/debug/ch30_closure_trait`
x is: 5
16

Example:可变应用的例子

  • 能写非mut的尽量写非mut的,因为mut和非mut的性能差距很大
rust">fn apply_closure<F: FnMut(i32, i32) -> i32>(mut closure: F, x: i32, y: i32) -> i32 {closure(x, y)
}fn main() {let mut x = 5;let mut add_closure = |a, b| {x += 1;println!("x is: {}", x);a + b + x};let result = apply_closure(add_closure, 5, 6);println!("{}", result);
}

编译及运行

 cargo runCompiling ch30_closure_trait v0.1.0 (/home/wangji/installer/rust/project/ch30_closure_trait)
warning: variable does not need to be mutable--> src/main.rs:7:9|
7 |     let mut add_closure = |a, b| {|         ----^^^^^^^^^^^|         ||         help: remove this `mut`|= note: `#[warn(unused_mut)]` on by defaultwarning: `ch30_closure_trait` (bin "ch30_closure_trait") generated 1 warning (run `cargo fix --bin "ch30_closure_trait"` to apply 1 suggestion)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.33sRunning `target/debug/ch30_closure_trait`
x is: 6
17

四、闭包类型FnOnce、FnMut和Fn做函数参数的实例

Example:

rust">// 只有不可变引用能用
fn closure_fn<F>(func: F)
whereF: Fn(),
{func();func();
}// 可变引用和不可变引用都可以接受
fn closure_fn_mut<F>(mut func: F)
whereF: FnMut(),
{func();func();
}// 可变引用和不可变引用都可以接受,具有修改所有权的能力!!
fn closure_fn_once<F>(func: F)
whereF: FnOnce(),
{func();
}fn main() {// 不可变引用只能传一种let s1 = String::from("11111");closure_fn(|| println!("{}", s1)); //性能第2// 可变引用let s1 = String::from("11111");closure_fn_mut(|| println!("{}", s1)); //性能最差// println!("{}", s1);let mut s2 = String::from("22222");closure_fn_mut(|| {s2.push_str("😀");println!("{}", s2);});println!("{s2}");println!("======================");// 所有权转移let s1 = String::from("11111");closure_fn_once(|| println!("{}", s1));let mut s2 = String::from("22222");closure_fn_once(|| {s2.push_str("😀");println!("{}", s2);});println!("{s2}");let s3 = " ff".to_owned();closure_fn_once(move || println!("{s3}")); //move主动修改所有权,性能最好// println!("{s3}")
}

编译及运行

 cargo runFinished `dev` profile [unoptimized + debuginfo] target(s) in 0.00sRunning `target/debug/ch31_fn`
11111
11111
11111
11111
22222😀
22222😀😀
22222😀😀
======================
11111
22222😀
22222😀ff

参考

  • 2024 Rust现代实用教程

http://www.ppmy.cn/devtools/131677.html

相关文章

【自然语言处理与大模型】大模型(LLM)基础知识②

&#xff08;1&#xff09;LLaMA输入句子的长度理论上可以无限长吗&#xff1f; 理论上来说&#xff0c;LLM大模型可以处理任意长度的输入句子&#xff0c;但实际上存在一些限制。下面是一些需要考虑的因素&#xff1a; 1. 计算资源&#xff1a;生成长句子需要更多的计算资源&a…

云渲染与汽车CGI图像技术优势和劣势

在数字时代&#xff0c;云渲染技术以其独特的优势在汽车CGI图像制作中占据了重要地位。云渲染通过利用云计算的分布式处理能力&#xff0c;将渲染任务分配给云端的服务器集群进行计算&#xff0c;从而实现高效、高质量的渲染效果。 这种技术的优势主要体现在以下几个方面&#…

如何产看SQL 查询的执行时间

要查看 SQL 查询的执行时间&#xff0c;尤其是毫秒级别&#xff0c;可以使用以下几种方法&#xff1a; 方法 1&#xff1a;使用 SET STATISTICS TIME 查看执行时间 SET STATISTICS TIME 会显示执行时间的详细信息&#xff0c;包括 CPU 时间和总耗时。启用后&#xff0c;SQL S…

react 18 react-router-dom V6 路由传参的几种方式

路由配置如下 label:"首页",meta:{title:"首页"}},{path: /,// <AutnToken><Layout></Layout></AutnToken>element:<Layout></Layout>,label:"首页",meta:{title:"首页"},children:[{path:/home,…

域名自动重定向8080端口无法访问后端服务问题

1.问题描述&#xff1a; 今天遇到个这样的问题&#xff0c;访问应用某个地址&#xff1a;http://域名/上下文 一直提示失败&#xff0c;会自动被后端重定向到8080端口&#xff0c;去掉url上的8080端口号再次访问&#xff0c;就正常 2.原因&#xff1a; 根本原因还是因…

推荐这五款免费项目管理软件让你轻松应对所有项目

项目经理推荐的这五款免费项目管理软件让你轻松应对所有项目。无论你的项目规模大小&#xff0c;或是所处的行业领域&#xff0c;这些工具都能提供强大的功能支持&#xff0c;助力你高效管理项目&#xff0c;提升团队协作效率。从任务分配、进度跟踪到资源调度&#xff0c;这些…

Linux中的软硬链接文件详解

概述 在Linux文件系统中&#xff0c;软连接&#xff08;Symbolic Link&#xff09;和硬连接&#xff08;Hard Link&#xff09;是两种重要的文件链接方式。它们都可以创建指向相同文件内容的多个“链接”&#xff0c;但在实现方式和特性上有所不同。 1. 硬连接&#xff08;Ha…

斯坦福医学部发布GPT润色本子教程

最近&#xff0c;斯坦福大学医学部在GitHub上发布了一份针对申请资源本子润色的详细指导&#xff0c;包括使用GPT和其他大型语言模型来提升学术写作质量的全面建议。本文将为大家梳理这些润色指令&#xff0c;帮助你更好地理解和利用AI工具来优化学术写作。 指令集合 1. 提升文…