文章目录
- 一、闭包基础概念
- 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现代实用教程