rust的几种闭包类型
1.rust实现Base64编码
2.rust的几种闭包类型
前提知识:
rust里面有move,copy,clone。
所有对象都有一个类型,具体所有权。
比如
#[derive(Debug)]
struct Complex {
real: f64,
imag: f64,
}
fn main() {
let a = Complex{real:1.,imag:2.};
let b = a;
println!("{:?}",a);
println!("{:?}",b);
}
会提示 println!("{:?}",a); ^ value borrowed here after move,因为b=a,会转移a的所有权到b,这就是move语义。
但是,我们把#[derive(Debug)] 改成 #[derive(Debug,Clone,Copy)]就可以编译通过运行了。
Complex的各种成员都是Clone,所以Complex可以派生实现Clone
Complex的各种成员都是Copy,所以Complex可以派生实现Copy
实现Copy以后,函数传参,或者b=a这样的操作,就不会转移所有权了。
Copy就是一个浅拷贝,只是把a这个结构体的数据完全复制了一遍,如果a里面一个成员是&str,str指向的是堆数据,copy以后,b也可以访问那个堆数据。
Clone是深拷贝,比如String.Clone,就会在堆上复制一模一样的字符串数据,构建新的String,指向那片内存
#![feature(unboxed_closures)]
#![feature(fn_traits)]
#[derive(Debug,Clone)]
struct OnceStr {
s:String,
}
impl OnceStr {
fn new(s: String) -> Self {
OnceStr { s }
}
}
impl FnOnce<(&str,)> for OnceStr {
type Output =();
extern "rust-call" fn call_once(self, s: (&str,)) -> Self::Output {
println!("this is in FnOnce {}",self.s);
let mut ss = self.s;
ss.push_str(s.0);
let os = Self::new(ss);
println!("FnOnce {:?}",os);
}
}
impl FnMut<(&str,)> for OnceStr {
extern "rust-call" fn call_mut(&mut self, s: (&str,)) -> Self::Output {
self.s.push_str(s.0);
println!("this is in FnMut {}",self.s);
}
}
impl Fn<(&str,)> for OnceStr {
extern "rust-call" fn call(&self, s: (&str,)) -> Self::Output {
println!("get {} this is in Fn {}",s.0,self.s);
}
}
fn main() {
let s = "hello".to_string();
let mut c = OnceStr::new(s);
c.clone().call_once(("aa",));
c.call_mut(("aa",));
c.call(("aa",));
c.call(("bb",));
c.call_mut(("cc",));
{
let mut s = "hello".to_string();
let mut c1 = move || {
s.push_str("!");
println!("c1 is called {s}");
};
call_once(c1.clone());
// call_once(c1);
call_mut(&mut c1);
call_mut(&mut c1);
call_mut(&mut c1);
c1.call_mut(()); //这种调用方法和OnceStr没有区别
c1.call_once(());
// test(&c1);
}
{
let mut s = "hello".to_string();
let c2 = || {
s.push_str("=");
println!("c2 {}",s);
};
call_once(c2); //-- value moved here
let mut c3 = || {
s.push_str("=");
println!("c3 {}",s);
};
call_mut(&mut c3);
call_mut(&mut c3);
c3.call_mut(());//这种调用方法和OnceStr没有区别
c3.call_mut(());
c3.call_once(());
}
{
let mut s = "hello".to_string();
let mut c3 = || {
println!("{}",s);
};
call_once(c3.clone());
call_once(c3);
call_once(c3);
call_mut(&mut c3);
call_mut(&mut c3);
call_mut_copy(c3);
call_mut_copy(c3);
call_fn(&c3);
call_fn(&c3);
call_fn_copy(c3);
call_fn_copy(c3);
c3.call_once(());//这种调用方法和OnceStr没有区别
c3.call_mut(());
c3.call(()); //普通闭包当然也可以直接调用Trait的方法。
}
// call_fn(&||c("aa"));
// call_fn(&||c("aa"));
call_one(&c); //这种调用方式和普通的闭包没有区别
call_two(&mut c);
// call_three(c);
call_three(c.clone());
call_two(&mut c);
}
fn call_one<F: Fn(&str)>(f:&F) {
f("one");
}
fn call_two<F: FnMut(&str)>(f:&mut F) {
f("two");
}
fn call_three<F: FnOnce(&str)>(f:F) {
f("three");
}
// 编译不能通过,传入引用,不能转移所有权
// fn test<F:FnOnce()>(f:&F) ->F::Output {
// (*f)()
// }
fn call_once<F:FnOnce()>(f:F) ->F::Output {
f()
}
fn call_mut_copy<F:FnMut()>(mut f:F)->F::Output {
f()
}
fn call_fn_copy<F:Fn()>(f:F)->F::Output {
f()
}
fn call_fn<F:Fn()>(f:&F)->F::Output {
f()
}
fn call_mut<F:FnMut()>(f:&mut F)->F::Output {
f()
}
rust的闭包可以近似理解成一个匿名的结构体。闭包捕获的变量,就是结构体的成员
例如
let mut s = "hello".to_string();
let c1 = move || {
s.push_str("!");
println!("c1 can be called once {s}");
};
c1在创建的时候,有一个String变量,类似于上面的结构体OnceStr,同时,C1是FnOnce,也是FnMut
由于String实现了Clone,所以C1也是可以Clone的
call_once(c1.clone());
// call_once(c1);
call_mut(&mut c1);
call_mut(&mut c1);
对于
let mut c3 = || {
s.push_str("=");
println!("c3 {}",s);
};
call_mut(&mut c3);
C3类似于一个匿名结构体,结构体里面有一个&mut String,既没有Copy,也没有Clone,同时是FnOnce,也是FnMut
调用call_once就会丧失所有权,但是可以多次调用call_mut进行修改
对于
let mut s = "hello".to_string();
let c3 = || {
println!("{}",s);
};
c3类似于只有&str的匿名结构体,既是Clone,也是Copy的。所以它可以被各种调用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】