Reputation: 13
I'm trying to call a mutable method inside a immutable scope with gives me: error[E0502]
.
I'm already understand why this error occurs but I'm struggle on how to fix it or how to do a different approach that works.
Here a MCVE
struct A {
list: Vec<i8>,
has_three: bool,
}
impl A {
pub fn new() -> Self {
Self {
list: vec![1,2,3],
has_three: false,
}
}
pub fn mutable_method(&mut self) {
for item in self.list.iter() {
self.mutable_method2(item);
}
}
fn mutable_method2(&mut self, item: &i8) {
let b: i8 = 3;
if item == &b {
self.has_three = true;
}
}
}
fn main() {
let mut a = A::new();
a.mutable_method();
}
And the Error received:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:15:13
|
14 | for item in self.list.iter() {
| ----------------
| |
| immutable borrow occurs here
| immutable borrow later used here
15 | self.mutable_method2(item);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
Upvotes: 1
Views: 112
Reputation: 654
You asked for another approach. If I correctly assume that your goal is to have has_three
be true if any entry is 3, that's much more easily done this way:
pub fn mutable_method(&mut self) {
self.has_three = self.list.iter().any(|&x| x == 3);
}
By the way, you need to make sure mutable_method
is actually called appropriately, otherwise you will end up in logically invalid states. That's not good practice. Consider extracting this to the constructing function already.
Some background
The underlying problem is that your initial approach wants to borrow self
mutably, while already borrowing it immutably. However, logically, your code is not obviously invalid, as you only borrow a part of the struct mutably that you do not also borrow immutably. This information is lost though.
We make the safety explicit by factoring into two implicit operations,
let tmp = self.list.iter().any(|&x| x == 3);
self.has_three = tmp;
which both operate on the struct in a 'clear fashion', either mutably or immutably. That is how you can approach such problems.
Upvotes: 1