Не может заимствовать `self.x` как неизменяемый, потому что`*self` также заимствован как изменяемый
Во-первых, пусть код говорит:
#[derive(Debug)]
struct Bar;
#[derive(Debug)]
struct Qux {
baz: bool
}
#[derive(Debug)]
struct Foo {
bars: Vec<Bar>,
qux: Qux,
}
impl Foo {
fn get_qux(&mut self) -> &mut Qux {
&mut self.qux
}
fn run(&mut self) {
// 1. Fails:
let mut qux = self.get_qux();
// 2. Works:
// let mut qux = &mut Qux { baz: false };
// 3. Works:
// let mut qux = &mut self.qux;
let qux_mut = &mut qux;
qux_mut.baz = true;
for bar in &self.bars {
println!("{:?}", bar);
}
}
}
fn main() {
println!("Hello, world!");
let mut foo = Foo { bars: vec!(), qux: Qux { baz: false } };
foo.run();
}
Это ошибки:
error[E0502]: cannot borrow `self.bars` as immutable because `*self` is also borrowed as mutable
--> src/main.rs:33:21
|
22 | let mut qux = self.get_qux();
| ---- mutable borrow occurs here
...
33 | for bar in &self.bars {
| ^^^^^^^^^ immutable borrow occurs here
...
36 | }
| - mutable borrow ends here
Если я раскомментирую либо 2.
или же 3.
почему он компилируется просто отлично? Вызываемая функция в 1.
не делает ничего радикально отличного от 2.
или же 3.
, Так почему же тогда 1.
не может скомпилировать?
Хотя есть много похожих названных вопросов, я не мог четко идентифицировать это как обман (кроме сообщения об ошибке, являющегося тем же самым), возможно из-за моего непонимания системы владения / заимствования в Rust.
1 ответ
В Rust компилятор останавливается на границе вызова функции при оценке универсальных параметров, которые включают в себя универсальные параметры времени жизни. В вашем случае 1 вы вызываете метод:
fn get_qux(&mut self) -> &mut Qux {
&mut self.qux
}
Эта функция указывает на то, что все self
будет заимствовано, и возвращаемая ссылка будет жить до тех пор, пока self
будут. В течение этого времени никакие другие заимствования (изменяемые или нет) самого себя или его компонентов не могут быть сделаны.
Во втором случае вы делаете совершенно новый Qux
это не имеет никакой привязанности к вашей структуре вообще. Это не очень хороший пример, потому что он имеет совсем другое значение. Если этот случай работает для вас, вы должны это сделать. Однако вы не будете изменять то же самое, что и в случае 1.
В третьем случае вы избегаете вызова функции. Это означает, что у компилятора есть немного больше информации о том, что именно заимствовано. В частности, он может видеть, что self.qux
вообще не взаимодействует с self.bars
, так что ошибки нет.
Вы можете заставить свой оригинальный пример работать, добавив новую область видимости:
fn run(&mut self) {
{
let mut qux = self.get_qux();
let qux_mut = &mut qux;
qux_mut.baz = true;
}
for bar in &self.bars {
println!("{:?}", bar);
}
}
Здесь искусственный охват четко определяет, где заканчивается изменчивый заем. Как только заем закончен, другим предметам разрешается делать новые заимствования.
Если вам нужно изменить qux
внутри цикла, тогда вы должны следовать третьему шаблону:
let mut qux = &mut self.qux;
for bar in &self.bars {
qux.baz = ! qux.baz;
println!("{:?}", bar);
}
Или проще:
for bar in &self.bars {
self.qux.baz = ! self.qux.baz;
println!("{:?}", bar);
}
Много раз вы можете реорганизовать свой код для создания новых структур, которые содержат информацию и инкапсулируют красивую границу мутации, чтобы сделать код подобным этому.