运行 后台工作和 return "cancellation"-关闭
Run background work and return "cancellation"-closure
我对 Rust 很陌生,所以这可能是一个初学者问题:假设我想启动一些在后台运行的异步操作,并通过函数调用停止它。所需的 API 如下所示:
let stop = show_loadbar("loading some data...").await;
// load data...
stop().await;
我的代码:
pub fn show_loadbar(text: &str) -> Box<dyn FnOnce() -> Box<dyn Future<Output=()>>>
{
let (sender, receiver) = channel::bounded::<()>(0);
let display = task::spawn(async move {
while receiver.try_recv().is_err() {
// show loadbar: xxx.await;
}
// cleanup: yyy.await;
});
// return a function which stops the load bar
Box::new(move || {
Box::new(async {
sender.send(()).await;
display.await;
})
})
}
我玩了很多(创建结构而不是函数和一些组合),但最后,我总是得到这样的错误:
error[E0373]: async block may outlive the current function, but it borrows `sender`, which is owned by the current function
--> src/terminal/loading.rs:23:24
|
23 | Box::new(async {
| ________________________^
24 | | sender.send(()).await;
| | ------ `sender` is borrowed here
25 | | display.await;
26 | | })
| |_________^ may outlive borrowed value `sender`
鉴于所描述的 API,是否有可能在 Rust 中实现这样的功能?
独立于此,Rust 的方法是什么?也许这个接口绝对不是 Rust 应该做的。
非常感谢
您看到的直接错误可以通过将 async
更改为 async move
来修复,以便它通过值而不是通过引用捕获 sender
。但是尝试使用您的代码会发现更多问题:
- 你不能(而且可能不需要)等待
show_loadbar()
,因为它本身不是异步的。
- 钉盒装未来可以期待。
- 有界
async_std
通道的容量不能为 0(如果给定 0,它会崩溃);
- 处理
sender.send()
返回的错误,例如打开它。
- (可选)通过返回
impl FnOnce(...)
而不是 Box<dyn FnOnce(...)>
来摆脱外框。
考虑到这些,代码将如下所示:
pub fn show_loadbar(_text: &str) -> impl FnOnce() -> Pin<Box<dyn Future<Output = ()>>> {
let (sender, receiver) = channel::bounded::<()>(1);
let display = task::spawn(async move {
while receiver.try_recv().is_err() {
// show loadbar: xxx.await;
}
// cleanup: yyy.await;
});
// return a function which stops the load bar
|| {
Box::pin(async move {
sender.send(()).await.unwrap();
display.await;
})
}
}
// usage example:
async fn run() {
let cancel = show_loadbar("xxx");
task::sleep(Duration::from_secs(1)).await;
cancel().await;
}
fn main() {
task::block_on(run());
}
我对 Rust 很陌生,所以这可能是一个初学者问题:假设我想启动一些在后台运行的异步操作,并通过函数调用停止它。所需的 API 如下所示:
let stop = show_loadbar("loading some data...").await;
// load data...
stop().await;
我的代码:
pub fn show_loadbar(text: &str) -> Box<dyn FnOnce() -> Box<dyn Future<Output=()>>>
{
let (sender, receiver) = channel::bounded::<()>(0);
let display = task::spawn(async move {
while receiver.try_recv().is_err() {
// show loadbar: xxx.await;
}
// cleanup: yyy.await;
});
// return a function which stops the load bar
Box::new(move || {
Box::new(async {
sender.send(()).await;
display.await;
})
})
}
我玩了很多(创建结构而不是函数和一些组合),但最后,我总是得到这样的错误:
error[E0373]: async block may outlive the current function, but it borrows `sender`, which is owned by the current function
--> src/terminal/loading.rs:23:24
|
23 | Box::new(async {
| ________________________^
24 | | sender.send(()).await;
| | ------ `sender` is borrowed here
25 | | display.await;
26 | | })
| |_________^ may outlive borrowed value `sender`
鉴于所描述的 API,是否有可能在 Rust 中实现这样的功能? 独立于此,Rust 的方法是什么?也许这个接口绝对不是 Rust 应该做的。
非常感谢
您看到的直接错误可以通过将 async
更改为 async move
来修复,以便它通过值而不是通过引用捕获 sender
。但是尝试使用您的代码会发现更多问题:
- 你不能(而且可能不需要)等待
show_loadbar()
,因为它本身不是异步的。 - 钉盒装未来可以期待。
- 有界
async_std
通道的容量不能为 0(如果给定 0,它会崩溃); - 处理
sender.send()
返回的错误,例如打开它。 - (可选)通过返回
impl FnOnce(...)
而不是Box<dyn FnOnce(...)>
来摆脱外框。
考虑到这些,代码将如下所示:
pub fn show_loadbar(_text: &str) -> impl FnOnce() -> Pin<Box<dyn Future<Output = ()>>> {
let (sender, receiver) = channel::bounded::<()>(1);
let display = task::spawn(async move {
while receiver.try_recv().is_err() {
// show loadbar: xxx.await;
}
// cleanup: yyy.await;
});
// return a function which stops the load bar
|| {
Box::pin(async move {
sender.send(()).await.unwrap();
display.await;
})
}
}
// usage example:
async fn run() {
let cancel = show_loadbar("xxx");
task::sleep(Duration::from_secs(1)).await;
cancel().await;
}
fn main() {
task::block_on(run());
}