调用异步闭包的 rust 定义函数?



假设我们有一些重复的异步代码来执行htttp调用, 现在我们要编写一个函数,该函数将采用与闭包相同的代码,并记录请求之前和之后的所有内容。

这是我想要在kotlin中实现的简化代码(Rust 专家只需查看下面的 rust 代码忽略 kotlin 示例)

suspend fun <A, B> logRequest(req: A, callable: suspend (A) -> B): B {
println("write down the request $req")
val rep: B = callable(req)
println("write down the response $rep")
return rep
}

这是一个 smiple 函数,它接受A类型的请求和一个闭包,该闭包将采取相同的A执行一些异步逻辑并返回一些B......请注意,关闭是可暂停的(异步)

这将像这样使用

val request = "REQUEST"
val response = logRequest(request) {
println("my closure uses '$it' and can do some async stuff")
delay(1.second) // that is async
"RESPONSE"
}

如果你运行它,你会得到输出

write down the request REQUEST
my closure uses 'REQUEST' and can do some async stuff
write down the response RESPONSE

现在尝试用 Rust 做完全相同的事情(我是新手)

use std::fmt::Display;
// ignore this
async fn delay(millis: i64) {}
fn log_request<A: Display, B: Display>(req: A, callable: impl FnOnce(A) -> B) -> B {
println!("write down the request {}", &req);
let rep: B = callable(req);
println!("write down the response {}", &rep);
rep
}
#[tokio::main]
async fn main() {
let request = "REQUEST";
let callable = |it: &str| -> &str {
println!("my closure uses '{}' and can do some async stuff", it);
// delay(1000).await; // uncommenting this
"RESPONSE"
};
let response = log_request(request, callable);
}

在 Rust 中执行此操作的正确方法是什么?

如果取消注释,延迟调用编译器将显示|it: &str| -> &str { is not async那么如何将其定义为异步... 由于我已经在异步范围内运行,我肯定应该能够调用异步闭包(相当于 Kotlin 中的可挂起函数)

Kotlin 和 Rust 示例之间的区别在于您的 Kotlinlog_requestsuspend我认为这与 Rust 中的asyncfn 相同。你也可以通过在 Rustasync中制作log_request来获得你想要的。这需要一些额外的步骤来等待log_request中的Future,并对函数定义进行一些调整。

log_request上添加async后,您需要将闭包的输出更改为返回Future<Output=C>C: Display的位置。然后,您需要await闭包的输出以实际获取可显示值。

另一个更改是在闭包定义本身中,因为闭包不是async,您需要通过从中返回Future来解决此问题。使用async {}块是这里的解决方案。

这些步骤会使某些类型属性无效,例如,闭包上的&str属性可以完全删除,如果要保留rep: B注释,则需要将其更改为rep: C

use std::fmt::Display;
use std::future::Future;
// ignore this
async fn delay(millis: i64) {}
async fn log_request<A: Display, B, C: Display>(req: A, callable: impl FnOnce(A) -> B) -> C
where
B: Future<Output = C>,
{
println!("write down the request {}", &req);
let rep: C = callable(req).await;
println!("write down the response {}", &rep);
rep
}
#[tokio::main]
async fn main() {
let request = "REQUEST";
let callable = |it| {
async move {
println!("my closure uses '{}' and can do some async stuff", it);
delay(1000).await; // uncommenting this
"RESPONSE"
}
};
let response = log_request(request, callable).await;
}

游乐场链接

最新更新