gpt4 book ai didi

rust - 从Rust中的函数返回异步函数

转载 作者:行者123 更新时间:2023-12-03 11:38:04 32 4
gpt4 key购买 nike

第1部分:返回异步函数的函数的签名应该是什么?

pub async fn some_async_func(arg: &str) {}

// What should be sig here?
pub fn higher_order_func(action: &str) -> ???
{
some_async_func
}

第2部分:如果基于action参数,higher_order_func必须返回async_func1或async_func2,则应该是sig。

如果有多种解决方案,我也有兴趣学习性能权衡。请注意,我想将函数本身作为fn指针或Fn *特征返回,而不是调用它的结果。

最佳答案

返回函数

返回实际的函数指针需要堆分配和包装器:

use std::future::Future;
use std::pin::Pin;

pub async fn some_async_func(arg: &str) {}

pub fn some_async_func_wrapper<'a>(arg: &'a str)
-> Pin<Box<dyn Future<Output=()> + 'a>>
{
Box::pin(some_async_func(arg))
}

pub fn higher_order_func<'a>(action: &str)
-> fn(&'a str) -> Pin<Box<dyn Future<Output=()> + 'a>>
{
some_async_func_wrapper
}

为什么要拳击? higher_order_func需要具有一个具体的返回类型,即函数指针。指向函数还必须具有具体的返回类型,这对于 async函数来说是不可能的,因为它返回的是不透明类型。从理论上讲,可以将返回类型写为 fn(&'a str) -> impl Future<Output=()> + 'a,但这需要编译器进行更多猜测,并且目前不支持。

如果您对 Fn而不是 fn没问题,则可以摆脱包装器:
pub async fn some_async_func(arg: &str) {}

pub fn higher_order_func<'a>(action: &str)
-> impl Fn(&'a str) -> Pin<Box<dyn Future<Output=()> + 'a>>
{
|arg: &'a str| {
Box::pin(some_async_func(arg))
}
}

要基于 action值返回不同的函数,您需要将闭包本身装箱,这是另外一个堆分配:

pub async fn some_async_func_one(arg: &str) {}
pub async fn some_async_func_two(arg: &str) {}

pub fn higher_order_func<'a>(action: &str)
-> Box<dyn Fn(&'a str) -> Pin<Box<dyn Future<Output=()> + 'a>>>
{
if action.starts_with("one") {
Box::new(|arg: &'a str| {
Box::pin(some_async_func_one(arg))
})
} else {
Box::new(|arg: &'a str| {
Box::pin(some_async_func_two(arg))
})
}
}

选择:返回 future

为简化起见,请考虑返回future本身而不是函数指针。这实际上是相同的,但是更好,并且不需要堆分配:

pub async fn some_async_func(arg: &str) {}

pub fn higher_order_func_future<'a>(action: &str, arg: &'a str)
-> impl Future<Output=()> + 'a
{
some_async_func(arg)
}

看起来,当调用 higher_order_func_future时, some_async_func正在执行-但这是 而不是。由于异步功能的工作方式,当您调用 some_async_func时,不会执行用户代码。函数调用返回一个 Future:当有人等待返回的将来时,实际的函数主体将仅在上执行

您可以使用与先前功能几乎相同的方式使用新功能:

// With higher order function returning function pointer
async fn my_function() {
let action = "one";
let arg = "hello";
higher_order_func(action)(arg).await;
}

// With higher order function returning future
async fn my_function() {
let action = "one";
let arg = "hello";
higher_order_func_future(action, arg).await;
}

再次注意,在两种情况下,当等待将来时,实际的some_async_func主体仅执行,即

如果您希望能够基于action值调用不同的异步函数,则需要再次装箱:

pub async fn some_async_func_one(arg: &str) {}
pub async fn some_async_func_two(arg: &str) {}

pub fn higher_order_func_future<'a>(action: &str, arg: &'a str)
-> Pin<Box<dyn Future<Output=()> + 'a>>
{
if action.starts_with("one") {
Box::pin(some_async_func_one(arg))
} else {
Box::pin(some_async_func_two(arg))
}
}

尽管如此,这只是一个堆分配,因此我强烈建议返回将来。我可以想像的唯一方案是,您想将盒装封闭保存在某个地方并多次使用时,哪种解决方案更好。在这种情况下,过多的分配仅发生一次,并且通过仅基于action调度一次调用(在进行关闭操作时),可以节省一些CPU时间。

关于rust - 从Rust中的函数返回异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66352455/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com