我使用tokio-rs在Rust中构建服务,并且对此技术堆栈感到满意。我现在正试图将包含写入的异步操作和借用检查器的困难时间联系起来。
我的简化最小代码示例如下:
git add --all --verbose
作为简短摘要,在异步准备步骤之后,我尝试运行另一个写入extern crate futures; // 0.1.21
use futures::Future;
use std::{cell::RefCell, rc::Rc};
trait RequestProcessor {
fn prepare(&self) -> Box<Future<Item = (), Error = ()>>;
fn process(&mut self, request: String) -> Box<Future<Item = (), Error = ()>>;
}
struct Service {
processor: Rc<RefCell<RequestProcessor>>,
}
impl Service {
fn serve(&mut self, request: String) -> Box<Future<Item = (), Error = ()>> {
let processor_clone = self.processor.clone();
let result_fut = self
.processor
.borrow()
.prepare()
.and_then(move |_| processor_clone.borrow_mut().process(request));
Box::new(result_fut)
}
}
fn main() {}
字段的异步操作。没有可变性,这对于普通的self
成员很容易,但是可变性会破坏它,产生以下错误:
Rc
我希望这应该有用,我不知道哪里仍然借用了可变引用。我认为error[E0597]: `processor_clone` does not live long enough
--> src/main.rs:22:32
|
22 | .and_then(move |_| processor_clone.borrow_mut().process(request));
| ^^^^^^^^^^^^^^^ - `processor_clone` dropped here while still borrowed
| |
| borrowed value does not live long enough
|
= note: values in a scope are dropped in the opposite order they are created
应该在返回未来之后释放处理器的process()
,因此编译错误不应该发生。
请您解释一下根本原因?如何将此示例更改为编译器接受?
答案 0 :(得分:7)
有时,如果将值拆分为多行,则更容易看到生命周期错误。让我们尝试使用有问题的闭包:
.and_then(move |_| {
let c = processor_clone;
let mut d = c.borrow_mut();
let e = d.process(request);
e
});
如果你编译它...它的工作原理。如果我们尝试重新组合这些行,我们可能会失败:
.and_then(move |_| {
let c = processor_clone;
c.borrow_mut().process(request)
});
这要工作:
.and_then(move |_| {
let c = processor_clone;
return c.borrow_mut().process(request);
});
唯一的区别是显式返回和分号。这与When returning the outcome of consuming a StdinLock, why was the borrow to stdin retained?非常相似,所以让我们尝试启用non-lexical lifetimes的其中一个答案的建议。这允许您的原始代码也可以编译。
TL; DR:这是Rust目前的借阅检查程序实施中的一个弱点,并且在某些时候会被神奇地修复。与此同时,我建议将其写成两行:
.and_then(move |_| {
let mut c = processor_clone.borrow_mut();
c.process(request)
});