[英]How can I use a channel between an async closure and my main thread in rust?
I am trying to use a channel to communicate between an event handler and the main thread of my program using async rust.我正在尝试使用通道在事件处理程序和我的程序的主线程之间使用异步 rust 进行通信。 The event handler in question is this one from the matrix-rust-sdk .
有问题的事件处理程序是来自 matrix-rust-sdk的事件处理程序。
I can see that this exact pattern is used in the code here .我可以看到这里的代码中使用了这个确切的模式。
But when I tried literally the same thing in my own code, it gives me a really strange lifetime error.但是当我在自己的代码中尝试同样的事情时,它给了我一个非常奇怪的终身错误。
error: lifetime may not live long enough
--> src/main.rs:84:13
|
80 | move |event: OriginalSyncRoomMessageEvent, room: Room| {
| ------------------------------------------------------
| | |
| | return type of closure `impl futures_util::Future<Output = ()>` contains a lifetime `'2`
| lifetime `'1` represents this closure's body
...
84 | / async move {
85 | | if let Room::Joined(room) = room {
86 | | if room.room_id() == room_id {
87 | | match event.content.msgtype {
... |
94 | | }
95 | | }
| |_____________^ returning this value requires that `'1` must outlive `'2`
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
I tried to make a much simpler example, and the weird lifetime error remains:我试图做一个更简单的例子,但奇怪的生命周期错误仍然存在:
use tokio::sync::mpsc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let (tx, _rx) = mpsc::channel(32);
let closure = move || async {
at.send("hi");
};
Ok(())
}
Gives me:给我:
error: lifetime may not live long enough
--> src/main.rs:9:27
|
9 | let closure = move || async {
| ___________________-------_^
| | | |
| | | return type of closure `impl Future<Output = ()>` contains a lifetime `'2`
| | lifetime `'1` represents this closure's body
10 | | at.send("hi");
11 | | };
| |_____^ returning this value requires that `'1` must outlive `'2`
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
So how can I use a channel in an async closure?那么如何在异步闭包中使用通道呢? Why doesn't my code work when the code in the matrix-rust-sdk does?
当 matrix-rust-sdk 中的代码可以工作时,为什么我的代码不工作?
I think you meant || async move
我想你的意思是
|| async move
|| async move
instead of move || async
|| async move
而不是move || async
move || async
. move || async
。
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
let (tx, _rx) = mpsc::channel(32);
let closure = || async move {
tx.send("hi").await.unwrap();
};
closure().await;
}
I think in most cases, |args| async move {}
我认为在大多数情况下,
|args| async move {}
|args| async move {}
is what you want to use if you want to create an async
closure.如果要创建
async
闭包,则要使用|args| async move {}
。 But I don't completely understand the differences either.但我也不完全理解这些差异。
For more infos, this might help: What is the difference between `|_|有关更多信息,这可能会有所帮助: `|_| 之间有什么区别? async move {}` and `async move |_|
异步移动 {}` 和 `异步移动 |_| {}` .
{}` .
I don't think your minimal example represents your actual problem of your real code, though.不过,我认为您的最小示例并不代表您的真实代码的实际问题。 This is a minimal example that represents the real problem:
这是一个代表真正问题的最小示例:
#[derive(Clone, Debug)]
struct RoomId(u32);
#[derive(Clone, Debug)]
struct Room {
id: RoomId,
}
impl Room {
fn room_id(&self) -> &RoomId {
&self.id
}
}
#[tokio::main]
async fn main() {
let dm_room = Room { id: RoomId(42) };
let dm_room_closure = dm_room.clone();
let closure = move || {
let room_id = dm_room_closure.room_id();
async move {
println!("{}", room_id.0);
}
};
closure().await;
}
error: lifetime may not live long enough
--> src/main.rs:23:9
|
20 | let closure = move || {
| -------
| | |
| | return type of closure `impl Future<Output = ()>` contains a lifetime `'2`
| lifetime `'1` represents this closure's body
...
23 | / async move {
24 | | println!("{}", room_id.0);
25 | | }
| |_________^ returning this value requires that `'1` must outlive `'2`
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
The real problem here is caused by the fact that room_id
contains a reference to dm_room_closure
, but dm_room_closure
does not get kept alive by the innermost async move
context.这里真正的问题是由于
room_id
包含对dm_room_closure
的引用,但dm_room_closure
并没有被最里面的async move
上下文保持活动状态。
To fix this, make sure that the async move
keeps dm_room_closure
alive by moving it in as well.要解决此问题,请确保
async move
也通过移动dm_room_closure
来保持活动状态。 In this case, this is as simple as creating the room_id
variable inside of the async move
:在这种情况下,这就像在
async move
内创建room_id
变量一样简单:
#[derive(Clone, Debug)]
struct RoomId(u32);
#[derive(Clone, Debug)]
struct Room {
id: RoomId,
}
impl Room {
fn room_id(&self) -> &RoomId {
&self.id
}
}
#[tokio::main]
async fn main() {
let dm_room = Room { id: RoomId(42) };
let dm_room_closure = dm_room.clone();
let closure = move || {
async move {
let room_id = dm_room_closure.room_id();
println!("{}", room_id.0);
}
};
closure().await;
}
42
So I finally fixed the error.所以我终于修复了这个错误。 It turns out that something in
Room
doesn't implement Copy
and therefore it was causing some sort of state sharing despite the Clone
s.事实证明,
Room
中的某些东西没有实现Copy
,因此尽管有Clone
,它还是导致了某种 state 共享。 I fixed it by passing the RoomId
as a string .我通过将
RoomId
作为字符串传递来修复它。 Since the lifetime error message is entirely opaque, there was no way to see which moved variable was actually causing the problem.由于生命周期错误消息是完全不透明的,因此无法查看哪个移动变量实际上导致了问题。 Off to file a compiler bug report.
关闭以提交编译器错误报告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.