我试图用时雄实现一个Promise系统,我模拟了回调和解析,这是代码:
use std::time::Duration;
use tokio::sync::oneshot::{channel};
use tokio::time::sleep;
async fn task_prom(callback: impl Fn(i32)) {
for x in 1..=10 {
if x == 10 {
callback(x);
}
sleep(Duration::from_secs(1)).await;
}
}
async fn handler() -> i32 {
let (tx, rx) = channel::<i32>();
task_prom(move |x| tx.send(x).unwrap()).await;
rx.await.unwrap()
}
#[tokio::main]
async fn main() {
let res = handler().await;
println!("{}", res);
}
当我尝试运行时,我得到这个错误:
error[E0507]: cannot move out of `tx`, a captured variable in an `Fn` closure
--> src\main.rs:17:24
|
16 | let (tx, rx) = channel::<i32>();
| -- captured outer variable
17 | task_prom(move |x| tx.send(x).unwrap()).await;
| -------- ^^ ------- `tx` moved due to this method call
| | |
| | move occurs because `tx` has type `tokio::sync::oneshot::Sender<i32>`, which does not implement the `Copy` trait
| captured by this `Fn` closure
|
note: `tokio::sync::oneshot::Sender::<T>::send` takes ownership of the receiver `self`, which moves `tx`
--> C:\Users\titof\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.28.1\src\sync\oneshot.rs:594:21
|
594 | pub fn send(mut self, t: T) -> Result<(), T> {
|
^^^^
我看到了时雄的文档,但我不知道为什么我有这个错误。谢谢。
2条答案
按热度按时间bf1o4zei1#
由于oneshot通道只能使用一次,因此不能捕获它,然后在
Fn
或FnMut
闭包中使用它。闭包必须使用它,所以它需要是一个FnOnce
闭包。不幸的是,这仍然无法编译。
Rust并不静态地知道for循环运行了多少次。它也不静态地知道if表达式中的哪个分支将运行。因此,您需要重新构造代码,以确保
callback
只运行一次。如何实现这一点取决于函数,但在这种情况下,您可以将其移动到循环之外。您还可以在
callback
调用的相同路径中插入return
。除了for循环中的迭代器和if、match和while中的条件,rust在何时可以进行分支方面非常聪明。
xzlaal3s2#
我不完全理解你在这里想做什么,但是你的代码可以通过将
impl Fn(i32)
改为impl FnOnce(i32)
来编译,然后在for
循环之后调用callback
一次,而不是在循环中:正如错误消息中提到的,
send
移出了tx
,所以闭包只能执行一次,所以你需要使用FnOnce
,这个trait表示一个函数只能被调用一次。然后你需要将callback
移出循环体,这样Rust就知道它只会被调用一次。所有这一切都是因为您使用的是一个只能发送一次的oneshot通道;只要您只需要执行一次回调,这就很好。如果您需要,其他通道将允许您多次调用
send
。编辑:修正了代码,以匹配@drewtato更详细的答案,因为这是更正确的(在回调执行后应该有一个最后的睡眠,我一开始错过了)。