2024 Rust现代实用教程 closures闭包

news/2024/11/5 21:54:08 标签: rust

文章目录

  • 一、闭包基础概念
    • 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 run
   Compiling 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 default

warning: `ch29_closure` (bin "ch29_closure") generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 12.22s
     Running `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}");
    // 捕获的参数强制move
    let s1 = String::from("1111");
    let move_fn = move || {
        println!("{s1}");
    }; // Fn : FnMut : FnOnce
    move_fn();
    // println!("{s1}");
    let s1 = String::from("1111");
    std::thread::spawn(move || println!("d  {s1}")); //move确保线程运行的时候,s1还在
}

编译及运行:

 cargo run
   Compiling 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 default

warning: `ch29_func` (bin "ch29_func") generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.35s
     Running `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 run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `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 run
   Compiling 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 default

warning: `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.33s
     Running `target/debug/ch30_closure_trait`
x is: 6
17

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

Example:

rust">// 只有不可变引用能用
fn closure_fn<F>(func: F)
where
    F: Fn(),
{
    func();
    func();
}

// 可变引用和不可变引用都可以接受
fn closure_fn_mut<F>(mut func: F)
where
    F: FnMut(),
{
    func();
    func();
}

// 可变引用和不可变引用都可以接受,具有修改所有权的能力!!
fn closure_fn_once<F>(func: F)
where
    F: 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 run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/ch31_fn`
11111
11111
11111
11111
22222😀
22222😀😀
22222😀😀
======================
11111
22222😀
22222😀
 ff

参考

  • 2024 Rust现代实用教程

http://www.niftyadmin.cn/n/5739884.html

相关文章

为什么学习Mybatis框架

1.简化数据库操作 Mybatis可以简化Java应用程序与数据库之间的交互&#xff0c;允许开发者以简单的方式执行SQL语句&#xff0c;并处理结果集。 2.灵活性 Mybatis提供了很多灵活性的配置选项&#xff0c;让开发者可以根据具体的需求定制SQL和映射。 3.支持原生SQL 与一些ORM框…

ViT Model

卷积神经网络本身具有先验知识&#xff1a; Locality&#xff1a;相邻的区域之间的相关性更高Translation equation&#xff1a;平移等变性 Transformer的时间复杂度在O(n^2)&#xff0c;n是序列长度&#xff0c;而图片的大小是224 * 224&#xff0c;Flatten之后太大了&#…

CSS 计数器:深入解析与高级应用

CSS 计数器&#xff1a;深入解析与高级应用 CSS 计数器是前端开发中一个强大但经常被忽视的功能。它们允许开发者创建和管理自定义的计数序列&#xff0c;这在处理复杂文档结构时尤其有用。本文将深入探讨 CSS 计数器的原理、用法&#xff0c;并展示一些高级应用示例。 什么是…

Freertos学习日志(1)-基础知识

目录 1.什么是Freertos&#xff1f; 2.为什么要学习RTOS&#xff1f; 3.Freertos多任务处理的原理 1.什么是Freertos&#xff1f; RTOS&#xff0c;即&#xff08;Real Time Operating System 实时操作系统&#xff09;&#xff0c;是一种体积小巧、确定性强的计算机操作系统…

齿轮类型及其几何学与啮合理论的分析与实现——基于李特文《齿轮几何学与啮合理论》的MATLAB程序探究,《齿轮几何学与啮合理论及其MATLAB程序实现》

齿轮、行星齿轮、端面齿轮、斜齿轮、非圆齿轮、圆弧齿轮……啮合理论、啮合原理、齿面求解、传动特性、接触分析tca、传动误差等技术matlab程序实现。 参照李特文《齿轮几何学与啮合理论》 ID:21450706743787164 用户_06541178 齿轮是机械传动中常用的零部件&#xff0c;广泛…

字符类型模糊查询优化案例一

在实际开中中经常会遇到 like %a 运算&#xff0c;一般在数据库中此种写法不能使用索引优化查询&#xff0c;本示例提供一个简单的优化思路 这里借鉴 oracle 的反向索引的设计理念 可以在该表结构的基础上增加一个新的字段&#xff0c;该字段为目标字段的 REVERSE 使用触发…

成都睿明智科技有限公司共赴抖音电商蓝海

在这个短视频风起云涌的时代&#xff0c;抖音作为现象级的社交媒体平台&#xff0c;不仅改变了人们的娱乐方式&#xff0c;更悄然间重塑了电商行业的格局。在这片充满机遇与挑战的蓝海中&#xff0c;成都睿明智科技有限公司凭借其敏锐的市场洞察力和专业的服务能力&#xff0c;…

算法专题:栈

目录 1. 删除字符串中的所有相邻重复项 1.1 算法原理 1.2 算法代码 2. 844. 比较含退格的字符串 2.1 算法原理 2.2 算法原理 3. 基本计算器 II 3.1 算法原理 3.2 算法代码 4. 字符串解码 4.1 算法原理 4.2 算法代码 5. 验证栈序列 5.1 算法原理 5.2 算法代码 1.…