以下代码无法编译,因为编译器认为
s
保留在 main
的范围内,而不是移入 spawn
的范围。为什么编译器不明白 s
不需要绑定到外部作用域并且可以移动到 spawn
的作用域?
struct MyStruct {}
impl MyStruct {
async fn run(&self) {
println!("Hello");
}
}
#[tokio::main]
async fn main() {
let s = MyStruct{};
tokio::task::spawn(s.run());
}
main()
错误:
[E0597] Error: `s` does not live long enough
╭─[command_21:1:1]
│
11 │ let s = S{};
· ┬
· ╰── binding `s` declared here
12 │ tokio::task::spawn(s.run());
· ───┬───
· ╰───── borrowed value does not live long enough
· │
· ╰───── argument requires that `s` is borrowed for `'static`
13 │ }
· ┬
· ╰── `s` dropped here while still borrowed
────╯
我找到了一些解决方法,但很高兴听到是否有更好的方法:
如果我更改 fn 签名以移动 self 而不是借用:
run(self) // removed the &.
或者,如果我无法更改签名,我可以在调用站点添加显式移动:
tokio::task::spawn(async move { s.run().await });
有更好的方法吗?
正如您提到的,显式
async move
块是最好的方法。
Future
返回的未命名run
类型借用了self
,但tokio::task::spawn
需要一个'static
未来(即不借用的未来)。您不能只是“将自己移至未来”,因为这需要 run
返回不同的类型。但是,您可以通过 async move
创建一个新的未来,其中包含 self
,并且只需调用 run
。