我正在尝试创建一个通用函数,它具有包装异步闭包的令人印象深刻的目标。因此,出于所有意图和目的,它将把闭包视为黑盒,并简单地在之前运行一些设置逻辑,在之后运行一些逻辑,具体取决于传入的闭包的返回值。
这里是到目前为止我已经整理好的 MRE 示例代码。我还在 Rust 中测试了它游乐场也是如此。
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 编译器一起工作的帮助或指示,这对我来说似乎不太友好。我觉得我已经奋斗了几个小时,但不够聪明或不够熟练,无法知道如何满足编译器规则。
我还查看了 从 Rust 中的函数返回异步函数< /a> 并获得相应使用 Box::pin
的提示。然而,我在为我的特定用例实现它时遇到了麻烦,即我想创建一个通用函数来包装一个特别返回 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
变成一个通用的或者可能只是重用F
,但此时我很高兴能够让它工作:-)
I'm trying to create a generic function that has the impressive goal of wrapping an async closure. So for all intents and purposes, it would treat the closure as a black box and simply run some setup logic before and some logic after, depending on the return value of the closure that is passed in.
Here is an MRE example code I have put together so far. I was also testing it out in the Rust playground as well.
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(())
})
}
}
I would appreciate any help or pointers on how to get this to work with the rust compiler, which doesn't seem too friendly to me here. I feel as I've struggled for hours but am not smart enough or skilled with rust enough to know how to satisfy the compiler rules.
I also checked out Return an async function from a function in Rust and have got the tip to use Box::pin
accordingly. However I'm having trouble implementing it for my specific use case, i.e. where I want to create a generic function to wrap a callable that returns a Future
in particular. Thanks and let me know if I need to clarify on anything.
Update: Thanks to help from @Jakub. Here is my revised (working) code below:
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(())
})
}
}
Side note: it would've been nice to wrap the dyn Future<Output = Result<(), HelpAnError>>
into a generic or perhaps just reuse the F
, but at this point I'm just glad that was able to get it working :-)
发布评论
评论(1)