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

2024 Rust现代实用教程 closures闭包

文章目录

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

一、闭包基础概念

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

1.如何使用闭包

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

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

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

Example:

#[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:

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:

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的性能差距很大
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:

// 只有不可变引用能用
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.kler.cn/a/379033.html

相关文章:

  • 【网络安全】开发中存在的重定向与Referer问题
  • Java面向对象 C语言字符串常量
  • 【运动的&足球】足球运动员球守门员裁判检测系统源码&数据集全套:改进yolo11-DBBNCSPELAN
  • Qt中的Model与View 2
  • 如何使用Web-Check和cpolar实现安全的远程网站监测与管理
  • C++和OpenGL实现3D游戏编程【连载17】——着色器进阶
  • 【高等数学】6向量与空间几何
  • C/C++(九)C语言与C++中的类型转换
  • 架构师:构建高效团队和解决技术问题的指南
  • HarmonyOS第一课 06 构建更加丰富的页面-习题解析
  • 从0开始学习shell脚本
  • Golang | Leetcode Golang题解之第530题二叉搜索树的最小绝对差
  • QT中的定时器与计时器
  • vue的路由的两种模式 hash与history 详细讲解
  • python+pptx:(一)占位符、文本框、段落操作
  • 【python】OpenCV—findContours(4.5)
  • 【原创分享】JVM服务调优实战
  • Vue+element-ui实现网页右侧快捷导航栏 Vue实现全局右侧快捷菜单功能组件
  • selenium自动搭建
  • 数字化装配助力柔性制造与快速换型,驱动效率飞跃
  • chrome编辑替换js文件的图文教程
  • STL--哈希
  • BeanDefinition体系架构(待...)
  • 大数据挖掘和数据挖掘有什么不一样?
  • (C#面向初学者的 .NET 的生成 AI) 第 2 部分-什么是 AI 和 ML?
  • Nginx 实现动态封禁IP,详细教程来了