Gue*_*OCs 1 smart-pointers move-semantics rust
我有关于发电机的这个问题:
use tokio::runtime::Runtime;
use tokio::task::JoinHandle;
use std::sync::Arc;
pub fn run(f: Box<dyn Fn() -> Result<(), ()> + Send>) {
f();
}
fn main() {
let x = Arc::new(0);
run(Box::new(move ||{
let rt = Runtime::new().unwrap();
let _t = rt.block_on(async move {
let y = x;
});
Ok(())
}));
}
Run Code Online (Sandbox Code Playgroud)
错误:
error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
--> src/main.rs:13:41
|
10 | let x = Arc::new(0);
| - captured outer variable
...
13 | let _t = rt.block_on(async move {
| _________________________________________^
14 | | let y = x;
| | -
| | |
| | move occurs because `x` has type `Arc<i32>`, which does not implement the `Copy` trait
| | move occurs due to use in generator
15 | | });
| |_________^ move out of `x` occurs here
Run Code Online (Sandbox Code Playgroud)
我不明白为什么x是借用的,如果在闭包和块中,我都使用move. 所以x应该移到rt.block_on的闭包。根本不应该借钱。
生成器是一个不稳定的特性,目前只在夜间可用,可以与其他语言(例如Javascript、Go、Python)中的生成器或协程进行比较。
生成器本质上是状态机,可以暂停执行yield,然后再次恢复,并有可能在每次转换中传递数据。这种模式非常适合异步编程,并且 Rust 编译器扩展了某些async代码以使用生成器,即使您不能在不启用夜间功能的情况下自己明确使用它们。
这些消息可能是一个错误,即这些消息没有正确地进行功能门控,或者对于async脱糖生成的代码与您自己明确编写的代码相比,呈现不同的错误可能太复杂了。
因此,让我们忽略生成器,这对于您的实际问题来说有点小题大做。
你正在x进入一个关闭:
let x = Arc::new(0);
run(Box::new(move ||{
// 'move' closure uses x so x is moved
}));
Run Code Online (Sandbox Code Playgroud)
然后闭包x再次移动到一个async块中。问题在于run接受一个Fn闭包的签名——一个不能修改其环境但可能被多次调用的闭包。但是,您提供的闭包在第一次被调用时会移动x到async块中,因此第二次调用它是无效的。
鉴于您已经说过您无法更改run为接受 an FnOnce,您需要f通过防止它移动来多次调用x。你可以通过克隆它来做到这一点:
fn main() {
let x = Arc::new(0);
run(Box::new(move || {
let rt = Runtime::new().unwrap();
// each time the closure is called, it will pass a clone of the Arc
// into the task, so it can be called more than once
let x = x.clone();
let _t = rt.block_on(async move {
let y = x;
});
Ok(())
}));
}
Run Code Online (Sandbox Code Playgroud)
整个设计Arc是关于廉价克隆的。它很便宜,因为它只复制指向您的数据的指针并增加引用计数,这就是它如何知道何时可以安全地释放保存其数据的内存。如果您从不克隆一个,Arc那么您几乎肯定一开始就不需要它!
| 归档时间: |
|
| 查看次数: |
213 次 |
| 最近记录: |