-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Motivation:
Currently you cannot borrow a value mutable why it is currently being borrowed. This is a core aspect of Rust and should not be removed, however, there are legitimate uses for wanting to do something like this and with the proposal this would become more easy to accomplish safely.
Example (of what is wanted to be done):
#[derive(PartialEq)]
struct Actor {
hp: i32,
attacking: bool,
}
impl Actor {
pub fn new() -> Actor {
Actor {
hp: 10,
attacking: false,
}
}
pub fn damage(&mut self) {
self.hp -= 1;
}
}
fn main() {
let mut actors = vec![Actor::new(), Actor::new()];
actors[1].attacking = true;
for actor in actors.iter_mut() {
//if an actor is attacking, damage all the other actors
if actor.attacking {
//doesnt compile due to two mut borrows
for actor2 in actors.iter_mut() {
if actor2 != actor {
actor2.damage();
}
}
}
}
}
This was taken from here.
There are ways to work around this currently but generally it requires convoluted methods or extra allocations which are undesirable especially for people coming to rust.
A working example that leaves most of the algorithm the same has the following main, gotten from here:
fn main() {
let actors = UnsafeCell::new(vec![Actor::new(), Actor::new()]);
unsafe {
(*actors.get())[1].attacking = true;
}
for actor in unsafe { (*actors.get()).iter_mut() } {
//if an actor is attacking, damage all the other actors
if actor.attacking {
for actor2 in unsafe { (*actors.get()).iter_mut() } {
if actor2 != actor {
actor2.damage();
}
}
}
}
}
Proposition:
A new type of borrowing, called immovable borrow
which can be done at any time, even when another item has borrowed it. This would only allow mutations that are guaranteed not to require a move. These would only be allowed with mutable borrows. To my knowledge most actions on intrinsics are no-move but there may be others.
This would be implemented by two item: iter_mut_immov()
which would be for generated mutable immovable references for iterating through and immov
which would be a keyword use in conjunction with &mut
(ie &mut immov
) for getting these sorts of borrows individually.
An error that recommends this type of borrow would also be implemented.
This proposal does ask for adding a new keyword or at least a new contextual keyword (then it would be &immov mut
)
Example:
Using this proposition the following would be done:
fn main() {
let mut actors = vec![Actor::new(), Actor::new()];
actors[1].attacking = true;
for actor in actors.iter() {
//if an actor is attacking, damage all the other actors
if actor.attacking {
//now with immovable borrow
for actor2 in actors.iter_mut_immov() {
if actor2 != actor {
actor2.damage();
}
}
}
}
}