【发布时间】:2021-02-08 15:17:23
【问题描述】:
trait Output {
fn write(&mut self, text: &str);
}
struct DummyOutput {}
impl Output for DummyOutput {
fn write(&mut self, text: &str) {
// self does not need to be mut in this reproducer,
// but it would in the real version
println!("{}", text);
}
}
enum EncoderOutput<'a, T> {
Owned(T),
Borrowed(&'a mut T),
}
impl<'a, T> AsMut<T> for EncoderOutput<'a, T> {
fn as_mut(&mut self) -> &mut T {
match self {
EncoderOutput::Owned(ref mut o) => o,
EncoderOutput::Borrowed(b) => b,
}
}
}
struct Encoder<'a, O: Output> {
output: EncoderOutput<'a, O>,
}
impl<'a, O: Output> Encoder<'a, O> {
// here's the idea:
// every child instance will have a borrowed output,
// and always only one level of indirection, i.e.:
// - root: "&mut O" or "O"
// - child1: "&mut O"
// - child2: "&mut O"
// but never:
// - childN: "&mut &mut O"
fn child(&'a mut self) -> Self {
Encoder {
output: EncoderOutput::Borrowed(self.output.as_mut()),
}
}
}
fn main() {
let mut enc1 = Encoder {
output: EncoderOutput::Owned(DummyOutput {}),
};
{
// I know this borrows mutably from enc1
let mut enc2 = enc1.child();
// so this will obviously not work:
// enc1.output.as_mut().write("bar 2b");
// but this does work:
enc2.output.as_mut().write("bar 2a");
} // but then the borrow "enc2" should be dropped here?
// so why does this fail with:
// "cannot borrow [...] as mutable more than once"
enc1.output.as_mut().write("bar 3");
}
error[E0499]: cannot borrow `enc1.output` as mutable more than once at a time
--> src/main.rs:68:5
|
57 | let mut enc2 = enc1.child();
| ---- first mutable borrow occurs here
...
68 | enc1.output.as_mut().write("bar 3");
| ^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
我的直觉告诉我这失败了,因为 child() 返回的 Encoder 中借用的生命周期与“父”具有相同的生命周期 - 但我看不到一种解耦生命周期的方法,即使返回值的生命周期显然应该小于或等于父值,因为它可以预先删除。
我也尝试过没有EncoderOutput 的版本,只是在Encoder 中直接有一个&mut O,但问题是一样的。
我的思路为什么这应该起作用:当main() 中的范围结束时,enc2 被删除,隐含的Drop impl 运行它,这会清理EncoderOutput::Borrowed 和其中的引用,因此没有其他 &mut 引用到 enc1,并且 enc1 可以再次可变借用。
我哪里错了?
【问题讨论】:
-
看来Cannot borrow as mutable more than once at a time in one code - but can in another very similar的答案可能会回答您的问题; Moved variable still borrowing after calling
drop?。如果没有,请edit您的问题来解释差异。否则,我们可以将此问题标记为已回答。
标签: generics rust lifetime borrow-checker borrowing