以下程序编译没有问题:
#[tokio::main]
async fn main() {
async fn g(x: String) {}
let f = || {
let y: String = String::from("a").clone();
return async {
println!("{}", &y);
return g(y).await;
}};
}
Run Code Online (Sandbox Code Playgroud)
但是,如果行“return g(y).await;” 被删除后,它将失败并出现以下情况:
error[E0373]: async block may outlive the current function, but it borrows `y`, which is owned by the current function
--> src/main.rs:35:22
|
35 | return async {
| ______________________^
36 | | println!("{}", &y);
| | - `y` is borrowed here
37 | | // return g(y).await;
38 | | }};
| |_____^ may outlive borrowed value `y`
|
note: async block is returned here
--> src/main.rs:35:16
|
35 | return async {
| ________________^
36 | | println!("{}", &y);
37 | | // return g(y).await;
38 | | }};
| |_____^
help: to force the async block to take ownership of `y` (and any other referenced variables), use the `move` keyword
|
35 | return async move {
| ++++
Run Code Online (Sandbox Code Playgroud)
为什么原来的代码中没有出现同样的错误呢?
Rust 做了让你的闭包工作所需的最少量的工作。
let f = || {
let y: String = String::from("a").clone();
return async {
println!("{}", &y);
}
};
Run Code Online (Sandbox Code Playgroud)
这里,内部闭包需要y通过引用。所以 Rust 本质上将把它变成 astruct和 a &String。为了简单起见,删除异步的东西,它会变成这样
let f = || {
let y: String = String::from("a").clone();
|| {
println!("{}", &y);
}
};
Run Code Online (Sandbox Code Playgroud)
有效地进入这个
struct MyCustomClosure<'a> { y: &'a String };
impl<'a> FnOnce for MyCustomClosure<'a> {
fn call_once(self) {
println!("{}", self.y)
}
}
// (Same impl for FnMut and Fn ...)
let f = || {
let y: String = String::from("a").clone();
return MyCustomClosure { y: &y }
};
Run Code Online (Sandbox Code Playgroud)
现在,在编译过程的后期'a,Rust 意识到for 的生命MyCustomClosure周期与封闭函数的生命周期不一致,并且它会抱怨。但到目前为止,它已经致力于在此处使用引用,并且还不够聪明,无法返回并尝试不同的闭包类型。这是两个不同的编译阶段,彼此不直接对话。
这另一方面
let f = || {
let y: String = String::from("a").clone();
|| { y }
};
Run Code Online (Sandbox Code Playgroud)
另一方面,这显然需要采取行动。我们在闭包内传递所有权,因此我们得到一个仅实现FnOnce并按值获取的闭包y。本质上我们得到
struct MyCustomClosure2 { y: String };
impl FnOnce for MyCustomClosure2 {
fn call_once(self) -> String {
self.y
}
}
// No FnMut or Fn this time, since we need to pass ownership of a value.
Run Code Online (Sandbox Code Playgroud)
现在,不再有终生争论'a会导致未来的冲突。只有一个简单的结构,一切顺利。
正如错误消息所示,如果您的意图是FnOnce通过移动来获取返回字符串,则可以在闭包前面加上move关键字。
let f = || {
let y: String = String::from("a").clone();
return async move {
println!("{}", &y);
}
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
105 次 |
| 最近记录: |