"cannot borrow as mutable more than once" 即使在放弃第一次借用之后
"cannot borrow as mutable more than once" even after dropping the first borrow
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
和其中的引用,因此不会留下 enc1
的其他 &mut
引用,并且 enc1
可以再次可变地借用。
我哪里出错了?
经过一番折腾,解决方案是将child
改为:
fn child(&mut self) -> Encoder<'_, O> {
Encoder {
output: EncoderOutput::Borrowed(self.output.as_mut()),
}
}
现在我知道问题出在一个方法的生命周期上,因此 rustc 推断主题(self)必须保持借用的时间不超过和超过它的寿命,所以一旦这个方法被调用你' d被“锁定”。遗憾的是,我不记得确切的问题或找到它的先前实例,尽管我知道它们存在。
因此,虽然我能想到可能的解释,但因为我不知道它们是否正确,所以我不会提供任何解释,抱歉。但基本上通过使用 '_
你告诉 rustc 给你一个新的输出生命周期并找出界限。
变化:
fn child(&'a mut self) -> Encoder<'a, O>;
收件人:
fn child(&mut self) -> Encoder<'_, O>;
修复编译示例:
trait Output {
fn write(&mut self, text: &str);
}
struct DummyOutput {}
impl Output for DummyOutput {
fn write(&mut self, text: &str) {
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> {
// line below changed from:
// fn child(&'a mut self) -> Encoder<'a, O> {
// to:
// child(&mut self) -> Encoder<'_, O> {
fn child(&mut self) -> Encoder<'_, O> {
Encoder {
output: EncoderOutput::Borrowed(self.output.as_mut()),
}
}
}
fn main() {
let mut enc1 = Encoder {
output: EncoderOutput::Owned(DummyOutput {}),
};
{
let mut enc2 = enc1.child();
enc2.output.as_mut().write("bar 2a");
}
enc1.output.as_mut().write("bar 3");
}
说明
&'a self
和 &'a mut self
是所有 Rust 中最常见的生命周期陷阱,大多数初学者甚至中级 Rustaceans 最终都会陷入其中。我一看到你的例子中的那一行就知道它是错误的,甚至没有试图理解你代码其余部分的任何其他内容。超过 99.9% 的时间 &'a self
和 &'a mut self
是错误的,无论何时你看到它们都应该发出一个大红旗,当你看到它们时,你应该积极地重构它们。好的,撇开这些不谈,这就是它们如此糟糕的原因:
如果你有一些包含引用的容器,我们称之为 Container<'a>
,那么容器的生命周期是多少?它与其引用的生命周期相同,因为容器不能比它所包含的内容更长寿。我们称其为生命周期 'a
。非常重要:Container<'a>
中的'a
代表容器的整个生命周期。因此,当您使用 &'a self
或 &'a mut self
接收器编写方法时,您与编译器通信的是 “为了调用此方法,该方法必须借用容器作为剩余部分它的整个生命周期。” 现在,您真正想要的是什么时候?几乎从来没有!极少需要编写只能调用一次的方法,因为它会在 self
的剩余生命周期中永久借用 self
。因此,&'a self
和 &'a mut self
是新手陷阱,请避开它们。
澄清
当 'a
代表 self
本身的整个生命周期时,&'a self
和 &'a mut self
只是危险信号。在像下面这样的场景中,'a
的范围仅限于一个方法,那就没问题了:
// 'a only local to this method, this is okay
fn method<'a>(&'a self) {
// etc
}
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
和其中的引用,因此不会留下 enc1
的其他 &mut
引用,并且 enc1
可以再次可变地借用。
我哪里出错了?
经过一番折腾,解决方案是将child
改为:
fn child(&mut self) -> Encoder<'_, O> {
Encoder {
output: EncoderOutput::Borrowed(self.output.as_mut()),
}
}
现在我知道问题出在一个方法的生命周期上,因此 rustc 推断主题(self)必须保持借用的时间不超过和超过它的寿命,所以一旦这个方法被调用你' d被“锁定”。遗憾的是,我不记得确切的问题或找到它的先前实例,尽管我知道它们存在。
因此,虽然我能想到可能的解释,但因为我不知道它们是否正确,所以我不会提供任何解释,抱歉。但基本上通过使用 '_
你告诉 rustc 给你一个新的输出生命周期并找出界限。
变化:
fn child(&'a mut self) -> Encoder<'a, O>;
收件人:
fn child(&mut self) -> Encoder<'_, O>;
修复编译示例:
trait Output {
fn write(&mut self, text: &str);
}
struct DummyOutput {}
impl Output for DummyOutput {
fn write(&mut self, text: &str) {
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> {
// line below changed from:
// fn child(&'a mut self) -> Encoder<'a, O> {
// to:
// child(&mut self) -> Encoder<'_, O> {
fn child(&mut self) -> Encoder<'_, O> {
Encoder {
output: EncoderOutput::Borrowed(self.output.as_mut()),
}
}
}
fn main() {
let mut enc1 = Encoder {
output: EncoderOutput::Owned(DummyOutput {}),
};
{
let mut enc2 = enc1.child();
enc2.output.as_mut().write("bar 2a");
}
enc1.output.as_mut().write("bar 3");
}
说明
&'a self
和 &'a mut self
是所有 Rust 中最常见的生命周期陷阱,大多数初学者甚至中级 Rustaceans 最终都会陷入其中。我一看到你的例子中的那一行就知道它是错误的,甚至没有试图理解你代码其余部分的任何其他内容。超过 99.9% 的时间 &'a self
和 &'a mut self
是错误的,无论何时你看到它们都应该发出一个大红旗,当你看到它们时,你应该积极地重构它们。好的,撇开这些不谈,这就是它们如此糟糕的原因:
如果你有一些包含引用的容器,我们称之为 Container<'a>
,那么容器的生命周期是多少?它与其引用的生命周期相同,因为容器不能比它所包含的内容更长寿。我们称其为生命周期 'a
。非常重要:Container<'a>
中的'a
代表容器的整个生命周期。因此,当您使用 &'a self
或 &'a mut self
接收器编写方法时,您与编译器通信的是 “为了调用此方法,该方法必须借用容器作为剩余部分它的整个生命周期。” 现在,您真正想要的是什么时候?几乎从来没有!极少需要编写只能调用一次的方法,因为它会在 self
的剩余生命周期中永久借用 self
。因此,&'a self
和 &'a mut self
是新手陷阱,请避开它们。
澄清
当'a
代表 self
本身的整个生命周期时,&'a self
和 &'a mut self
只是危险信号。在像下面这样的场景中,'a
的范围仅限于一个方法,那就没问题了:
// 'a only local to this method, this is okay
fn method<'a>(&'a self) {
// etc
}