如何创建一个通用函数来包装异步闭包?
How to create a generic function to wrap an async closure?
我正在尝试创建一个通用函数,它具有包装异步闭包的令人印象深刻的目标。因此,出于所有意图和目的,它会将闭包视为 黑盒 并且只是 运行 之前的一些设置逻辑和之后的一些逻辑,具体取决于 return传入的闭包值。
这是我到目前为止整理的 MRE 示例代码。我也在 Rust playground 中对其进行了测试。
use std::future::Future;
use std::pin::Pin;
#[derive(Default)]
struct MyEvent {}
#[derive(Default)]
struct MyContext {
pub fn_name: String,
}
pub struct HelpAnError {}
#[tokio::main]
async fn main() {
let my_age: u8 = 29;
let doing_work_hard = move |event: MyEvent, ctx: MyContext| async move {
println!("I'm working hard, i promise!");
println!("Ma i'm already {} yrs old!", my_age);
Ok::<_, HelpAnError>(())
};
let doing_chores_hard = lets_wrap_da_closure(doing_work_hard);
// does all the chores that Ma assigned to me
let _ = doing_chores_hard(Default::default(), Default::default()).await;
}
fn lets_wrap_da_closure<
C: Fn(MyEvent, MyContext) -> F,
F: Future<Output = Result<(), HelpAnError>>,
>(
do_work_hard: C,
) -> fn(MyEvent, MyContext) -> Pin<Box<dyn Future<Output = Result<(), HelpAnError>>>> {
move |event: MyEvent, ctx: MyContext| {
Box::pin(async move {
println!("I'm doin my chores Ma, I promise!");
// **help** - if I uncomment this it fails!
// do_work_hard(event, ctx).await;
println!("Yay! The chores are now complit.");
Ok(())
})
}
}
对于如何使它与 rust 编译器一起工作的任何帮助或指示,我将不胜感激,这对我来说似乎不太友好。我觉得我已经奋斗了几个小时,但我不够聪明,也不够熟练,无法知道如何满足编译器规则。
我也检查了 并得到了相应使用 Box::pin
的提示。但是,我在针对我的特定用例实现它时遇到了麻烦,即我想创建一个通用函数来包装一个可调用对象,特别是 return 是一个 Future
。谢谢,如果我需要澄清任何事情,请告诉我。
更新:感谢@Jakub 的帮助。下面是我修改后的(工作)代码:
use std::future::Future;
use std::pin::Pin;
#[derive(Default)]
struct MyEvent {}
#[derive(Default)]
struct MyContext {
pub fn_name: String,
}
#[derive(Debug)]
pub struct HelpAnError {}
#[tokio::main]
async fn main() {
let my_age: u8 = 29;
let doing_work_hard = move |event: MyEvent, ctx: MyContext| async move {
println!("I'm working hard, i promise!");
println!("Ma i'm already {} yrs old!", my_age);
Ok::<_, HelpAnError>(())
};
let doing_chores_hard = lets_wrap_da_closure(doing_work_hard);
// does all the chores that Ma assigned to me
let _ = doing_chores_hard(Default::default(), Default::default()).await;
}
fn lets_wrap_da_closure<
'a,
C: Fn(A1, A2) -> F,
A1,
A2,
E: std::fmt::Debug,
F: Future<Output = Result<(), E>> + 'a,
>(
do_work_hard: C,
) -> impl Fn(A1, A2) -> Pin<Box<dyn Future<Output = Result<(), E>> + 'a>> {
move |event: A1, ctx: A2| {
let fut = do_work_hard(event, ctx);
Box::pin(async move {
println!("I'm doin my chores Ma, I promise!");
// it WORKS! wow, amazing ~
match fut.await {
Ok(_) => println!("All systems are a GO!"),
Err(e) => println!("I ran into issue doing my chores: {:?}", e),
};
println!("Yay! The chores are now complit.");
Ok(())
})
}
}
旁注:将 dyn Future<Output = Result<(), HelpAnError>>
包装成通用的或者可能只是重复使用 F
会很好,但在这一点上我很高兴能够让它工作:-)
use std::future::Future;
use std::pin::Pin;
#[derive(Default)]
struct MyEvent {}
#[derive(Default)]
struct MyContext {
pub fn_name: String,
}
pub struct HelpAnError {}
#[tokio::main]
async fn main() {
let my_age: u8 = 29;
let doing_work_hard = move |event: MyEvent, ctx: MyContext| async move {
println!("I'm working hard, i promise!");
println!("Ma i'm already {} yrs old!", my_age);
Ok::<_, HelpAnError>(())
};
let doing_chores_hard = lets_wrap_da_closure(doing_work_hard);
// does all the chores that Ma assigned to me
let _ = doing_chores_hard(Default::default(), Default::default()).await;
}
fn lets_wrap_da_closure<
C: Fn(MyEvent, MyContext) -> F + 'static,
F: Future<Output = Result<(), HelpAnError>> + 'static,
>(
do_work_hard: C,
) -> impl Fn(MyEvent, MyContext) -> Pin<Box<dyn Future<Output = Result<(), HelpAnError>>>> {
move |event: MyEvent, ctx: MyContext| {
// this is the only way i can satisfy the compiler, do not worry,
// future will get executed only upon await and this call is just
// creating the future we are passing
let fut = do_work_hard(event, ctx);
Box::pin(async move {
println!("I'm doin my chores Ma, I promise!");
// **help** - if I uncomment this it fails!
drop(fut.await);
println!("Yay! The chores are now complit.");
Ok(())
})
}
}
我正在尝试创建一个通用函数,它具有包装异步闭包的令人印象深刻的目标。因此,出于所有意图和目的,它会将闭包视为 黑盒 并且只是 运行 之前的一些设置逻辑和之后的一些逻辑,具体取决于 return传入的闭包值。
这是我到目前为止整理的 MRE 示例代码。我也在 Rust playground 中对其进行了测试。
use std::future::Future;
use std::pin::Pin;
#[derive(Default)]
struct MyEvent {}
#[derive(Default)]
struct MyContext {
pub fn_name: String,
}
pub struct HelpAnError {}
#[tokio::main]
async fn main() {
let my_age: u8 = 29;
let doing_work_hard = move |event: MyEvent, ctx: MyContext| async move {
println!("I'm working hard, i promise!");
println!("Ma i'm already {} yrs old!", my_age);
Ok::<_, HelpAnError>(())
};
let doing_chores_hard = lets_wrap_da_closure(doing_work_hard);
// does all the chores that Ma assigned to me
let _ = doing_chores_hard(Default::default(), Default::default()).await;
}
fn lets_wrap_da_closure<
C: Fn(MyEvent, MyContext) -> F,
F: Future<Output = Result<(), HelpAnError>>,
>(
do_work_hard: C,
) -> fn(MyEvent, MyContext) -> Pin<Box<dyn Future<Output = Result<(), HelpAnError>>>> {
move |event: MyEvent, ctx: MyContext| {
Box::pin(async move {
println!("I'm doin my chores Ma, I promise!");
// **help** - if I uncomment this it fails!
// do_work_hard(event, ctx).await;
println!("Yay! The chores are now complit.");
Ok(())
})
}
}
对于如何使它与 rust 编译器一起工作的任何帮助或指示,我将不胜感激,这对我来说似乎不太友好。我觉得我已经奋斗了几个小时,但我不够聪明,也不够熟练,无法知道如何满足编译器规则。
我也检查了 Box::pin
的提示。但是,我在针对我的特定用例实现它时遇到了麻烦,即我想创建一个通用函数来包装一个可调用对象,特别是 return 是一个 Future
。谢谢,如果我需要澄清任何事情,请告诉我。
更新:感谢@Jakub 的帮助。下面是我修改后的(工作)代码:
use std::future::Future;
use std::pin::Pin;
#[derive(Default)]
struct MyEvent {}
#[derive(Default)]
struct MyContext {
pub fn_name: String,
}
#[derive(Debug)]
pub struct HelpAnError {}
#[tokio::main]
async fn main() {
let my_age: u8 = 29;
let doing_work_hard = move |event: MyEvent, ctx: MyContext| async move {
println!("I'm working hard, i promise!");
println!("Ma i'm already {} yrs old!", my_age);
Ok::<_, HelpAnError>(())
};
let doing_chores_hard = lets_wrap_da_closure(doing_work_hard);
// does all the chores that Ma assigned to me
let _ = doing_chores_hard(Default::default(), Default::default()).await;
}
fn lets_wrap_da_closure<
'a,
C: Fn(A1, A2) -> F,
A1,
A2,
E: std::fmt::Debug,
F: Future<Output = Result<(), E>> + 'a,
>(
do_work_hard: C,
) -> impl Fn(A1, A2) -> Pin<Box<dyn Future<Output = Result<(), E>> + 'a>> {
move |event: A1, ctx: A2| {
let fut = do_work_hard(event, ctx);
Box::pin(async move {
println!("I'm doin my chores Ma, I promise!");
// it WORKS! wow, amazing ~
match fut.await {
Ok(_) => println!("All systems are a GO!"),
Err(e) => println!("I ran into issue doing my chores: {:?}", e),
};
println!("Yay! The chores are now complit.");
Ok(())
})
}
}
旁注:将 dyn Future<Output = Result<(), HelpAnError>>
包装成通用的或者可能只是重复使用 F
会很好,但在这一点上我很高兴能够让它工作:-)
use std::future::Future;
use std::pin::Pin;
#[derive(Default)]
struct MyEvent {}
#[derive(Default)]
struct MyContext {
pub fn_name: String,
}
pub struct HelpAnError {}
#[tokio::main]
async fn main() {
let my_age: u8 = 29;
let doing_work_hard = move |event: MyEvent, ctx: MyContext| async move {
println!("I'm working hard, i promise!");
println!("Ma i'm already {} yrs old!", my_age);
Ok::<_, HelpAnError>(())
};
let doing_chores_hard = lets_wrap_da_closure(doing_work_hard);
// does all the chores that Ma assigned to me
let _ = doing_chores_hard(Default::default(), Default::default()).await;
}
fn lets_wrap_da_closure<
C: Fn(MyEvent, MyContext) -> F + 'static,
F: Future<Output = Result<(), HelpAnError>> + 'static,
>(
do_work_hard: C,
) -> impl Fn(MyEvent, MyContext) -> Pin<Box<dyn Future<Output = Result<(), HelpAnError>>>> {
move |event: MyEvent, ctx: MyContext| {
// this is the only way i can satisfy the compiler, do not worry,
// future will get executed only upon await and this call is just
// creating the future we are passing
let fut = do_work_hard(event, ctx);
Box::pin(async move {
println!("I'm doin my chores Ma, I promise!");
// **help** - if I uncomment this it fails!
drop(fut.await);
println!("Yay! The chores are now complit.");
Ok(())
})
}
}