This question already has answers here:
Modifying one attribute of a struct while iterating over another attribute
(4 answers)
Closed last month.
I want to iterate over a vector (or map) of actors in a world struct. The actors need access to the world as they might need to get information about the world, but can also change the state of the world. I should this be done properly in rust?
struct Actor {
}
impl Actor {
pub fn step(&mut self, world: &mut World) {
world.act();
}
}
struct World {
actors: Vec<Actor>,
state: u32
}
impl World {
pub fn step(&mut self) {
for actor in self.actors.iter_mut() {
actor.step(self);
}
}
pub fn act(&mut self) {
self.state += 1;
}
}
fn main() {
}
This code give the error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:18:24
|
17 | for actor in self.actors.iter_mut() {
| ----------------------
| |
| first mutable borrow occurs here
| first borrow later used here
18 | actor.step(self);
| ^^^^ second mutable borrow occurs here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `actors` due to previous error
You can't. It is impossible to mutate something while iterating over it, and in your current layout, Actor::step() would have the power to modify the actors list. So your situation is impossible, and Rust is correct that it shouldn't be allowed.
The real question is: Does your step function really require the list of actors? If not, I would solve the situation by splitting the list of actors and the state into two objects. That way, you can iterate over actors while only modifying state:
struct Actor {}
impl Actor {
pub fn step(&mut self, state: &mut WorldState) {
state.act();
}
}
struct WorldState {
some_value: u32,
}
struct World {
actors: Vec<Actor>,
state: WorldState,
}
impl World {
pub fn step(&mut self) {
for actor in self.actors.iter_mut() {
actor.step(&mut self.state);
}
}
}
impl WorldState {
pub fn act(&mut self) {
self.some_value += 1;
}
}
A somewhat simple solution is to pass exactly what you need.
impl Actor {
fn step(&mut self, state: &mut u32) {
*state += 1;
}
}
impl World {
pub fn step(&mut self) {
for actor in self.actors.iter_mut() {
actor.step(&mut self.state);
}
}
}
Related
Stripped down to the bare essentials, my problematic code looks as follows:
pub struct Item;
impl Item {
/// Partial copy. Not the same as simple assignment.
pub fn copy_from(&mut self, _other: &Item) {
}
}
pub struct Container {
items: Vec<Item>,
}
impl Container {
pub fn copy_from(&mut self, self_idx: usize, other: &Container, other_idx: usize) {
self.items[self_idx].copy_from(&other.items[other_idx]);
}
}
fn main() {
let mut container = Container { items: vec![Item, Item] };
container.copy_from(0, &container, 1);
}
This is of course rejected by the borrow checker:
error[E0502]: cannot borrow `container` as mutable because it is also borrowed as immutable
--> src/main.rs:21:5
|
21 | container.copy_from(0, &container, 1);
| ^^^^^^^^^^---------^^^^----------^^^^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
I understand why that happens, but I don't have a good solution.
I've considered adding a dedicated copy_from_self function that callers need to use in cases where self == other:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
if to_idx != from_idx {
unsafe {
let from_item: *const Item = &self.items[from_idx];
self.items[to_idx].copy_from(&*from_item);
}
}
}
But this is un-ergonomic, bloats the API surface, and needs unsafe code inside.
Note that in reality, the internal items data structure is not a simple Vec, so any approach specific to Vec or slice will not work.
Is there an elegant, idiomatic solution to this problem?
If I understand the comments on the question correctly, a general solution seems to be impossible, so this answer is necessarily specific to my actual situation.
As mentioned, the actual data structure is not a Vec. If it were a Vec, we could use split_at_mut to at least implement copy_from_self safely.
But as it happens, my actual data structure is backed by a Vec, so I was able to add a helper function:
/// Returns a pair of mutable references to different items. Useful if you need to pass
/// a reference to one item to a function that takes `&mut self` on another item.
/// Panics if `a == b`.
fn get_mut_2(&mut self, a: usize, b: usize) -> (&mut T, &mut T) {
assert!(a != b);
if a < b {
let (first, second) = self.items.split_at_mut(b);
(&mut first[a], &mut second[0])
} else if a > b {
let (first, second) = self.items.split_at_mut(a);
(&mut second[0], &mut first[b])
} else {
panic!("cannot call get_mut_2 with the same index {} == {}", a, b);
}
}
Now we can implement copy_from_self without unsafe code:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
let (to, from) = self.items.get_mut_2(to_idx, from_idx);
to.unwrap().copy_from(from.unwrap());
}
How should I rewrite the following code idiomatically?
The problem seems to be that traversal could be modified during action(). One solution would be to create a temporary copy of traversal inside of traverse, but that would be a burden if traversal is large.
Maybe Idiomatically access an element of a vector mutably and immutably is the canonical version of this, but I am not sure (and have not fully understood the referenced issue)?
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
// mutate self.arena[foo_idx]
}
fn traverse(&mut self) {
for i in &self.traversal {
self.action(*i);
}
}
}
current error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:15:13
|
14 | for i in &self.traversal {
| ---------------
| |
| immutable borrow occurs here
| immutable borrow later used here
15 | self.action(*i);
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
In your case, Bar has two apparently disjoint fields, so it should be possible to hold references to each of them at the same time. The problem, though, is even though action only touches arena, rust assesses the borrowing rules based on the function's prototype:
fn action(&mut self, foo_idx: usize)
which indicates that it takes a mutable borrow of self.
Here are a few possible solutions:
Inline
If the mutation being performed inside action is simple, and isn't called from anywhere else, then just do it inline inside traverse:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn traverse(&mut self) {
for i in &self.traversal {
// mutate arena here
self.arena[*i] = Foo{};
}
}
}
Refactor
If traversal and arena are really two different things, maybe it makes more sense for them to belong to separate types, like this:
struct Foo {}
struct Baz(Vec<Foo>);
impl Baz {
fn action(&mut self, foo_idx: usize) {
self.0[foo_idx] = Foo{};
}
}
struct Bar {
traversal: Vec<usize>,
arena: Baz,
}
impl Bar {
fn traverse(&mut self) {
for i in &self.traversal {
self.arena.action(*i);
}
}
}
Associated Function
A variation on the above theme is to simply change the prototype of action so that it takes only the field it will modify as input. action is no longer a method as such - it does not take self - but is still associated with the type Bar:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(arena: &mut Vec<Foo>, foo_idx: usize) {
arena[foo_idx] = Foo{};
}
fn traverse(&mut self) {
for i in &self.traversal {
Self::action(&mut self.arena, *i);
}
}
}
Traverse via index
Instead of iterating the traversal Vec, you can avoid taking the initial immutable borrow like this:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
// mutate self.arena[foo_idx]
}
fn traverse(&mut self) {
for traversal_idx in 0..self.traversal.len() {
let i = self.traversal[traversal_idx];
self.action(i);
}
}
}
I can think of two ways to do this (plus an easier way that's less general). The first is to destructure the struct so you aren't dealing with self anymore, but only its data. Then the data are independent so you the ownership of arena and traverse won't conflict anymore because they are independent. The disadvantage is that the function parameters get more complex.
struct Foo {
pub i: i32,
}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(arena: &mut Vec<Foo>, foo_idx: usize) {
arena[foo_idx].i += 1;
}
fn traverse(&mut self) {
let Bar { traversal, arena } = self;
for i in traversal {
Self::action(arena, *i);
}
}
}
The other way has a nicer API but is more risky: take just one value out of self (use std::mem::take or std::mem::replace) so you can reference it with no dependency on self. This is a liability is because you need to remember to put the value back in afterwards, and if you are using Result, ? can make the function return early and not execute the cleanup.
struct Foo {
pub i: i32,
}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
self.arena[foo_idx].i += 1;
}
fn traverse(&mut self) {
let traversal = std::mem::take(&mut self.traversal);
for i in traversal.iter() {
self.action(*i);
}
self.traversal = traversal;
}
}
If your real code is only iterating as in this example, there is an easier way to solve it: change the vector to Rc<Vec<Foo>>. That way you can use Rc::clone to get a copy of the variable that's independent of self, but points at the same data.
I want to downpass a mutable object, so that the entity responsible for working and managing certain aspects of the application can change parts of the world... for example make a bunny appear if a particular item fades away.
pub struct World {
world_items: WorldItemManager
}
impl World {
pub fn new() -> World {
World {
world_items: WorldItemManager{},
}
}
pub fn process(&mut self) {
//
// Uncomment to make it fail:
//
//self.world_items.process(&mut self);
}
}
pub struct WorldItemManager {
// items, events, anything that it should own
}
impl WorldItemManager {
pub fn process(&mut self, _world: &mut World) {
// If the sun stands at the exact spot, it makes something in the _world appear.
// Also: yes, if I don't take a _world argument it compiles. But.. that's the point.
}
}
struct Game {
world: World
}
impl Game {
pub fn new() -> Game {
Game {
world: World::new(),
}
}
pub fn run(&mut self) {
loop {
self.world.process();
}
}
}
fn main() {
let mut game = Game::new();
game.run();
}
I know that I can fix this by..
not passing the World at all
making the World not mutable in the manager
putting all the logic of the manager directly in world
I'm not looking for those, as I just want to find out how I can have a normal object graph where I can downpass what needs changing without making everything so cumbersome. It should be simple, but I can't get it to work:
error[E0499]: cannot borrow `self.world_items` as mutable more than once at a time
--> src/main.rs:16:9
|
16 | self.world_items.process(&mut self);
| ^^^^^^^^^^^^^^^^^-------^---------^
| | | |
| | | first mutable borrow occurs here
| | first borrow later used by call
| second mutable borrow occurs here
How can I downpass myself to a child of myself?
I am trying to implement Gale-Shapley algorithm in Rust and I need to declare a recursive struct like this:
#[derive(Eq, PartialEq, PartialOrd)]
struct Person {
name: char,
preference: Vec<Person>,
pref_index: usize,
candidates: Vec<Person>,
partner: Option<Box<Person>>, // using Box makes it easier to declare recursive structs
}
impl Person {
fn propose_to_next(&mut self) {
/* propose to next most preferred person */
if self.pref_index >= self.preference.len() {
()
}
let person = self.preference[self.pref_index];
self.candidates.push(person);
self.pref_index += 1;
}
fn pick_preferred(&mut self) {
/* pick the next more preferred partner or stay with the current one */
for person in &self.preference {
let p = Some(Box::new(*person));
if p == self.partner {
break;
} else if self.candidates.contains(&person) {
self.partner = p;
break;
}
}
}
}
But this gives me the error
error[E0507]: cannot move out of index of `std::vec::Vec<Person>`
--> src/lib.rs:18:22
|
18 | let person = self.preference[self.pref_index];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| move occurs because value has type `Person`, which does not implement the `Copy` trait
| help: consider borrowing here: `&self.preference[self.pref_index]`
error[E0507]: cannot move out of `*person` which is behind a shared reference
--> src/lib.rs:29:35
|
29 | let p = Some(Box::new(*person));
| ^^^^^^^ move occurs because `*person` has type `Person`, which does not implement the `Copy` trait
How do I fix this? Is my approach flawed? I tried a non OO approach using just vectors and hashmaps but it is ugly since I will have to pass in everything in every function.
This should probably do it in your case.
Notice how the struct doesn't have ownership of either the elements of the preference vector or the partner but just holds a (static for simplicitly) reference to them.
Notice also that you have to implement the PartialEq trait for this to work
use std::vec::Vec;
struct Person {
name: char,
preference: Vec<&'static Person>,
partner: Option<&'static Person>
}
impl Person {
fn pick_preferred(&mut self, candidates: &Vec<Person>) {
for person in &self.preference {
if candidates.contains(&person) {
self.partner = Some(person);
}
}
}
}
impl PartialEq for Person {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
pub fn main() {
let candidates: Vec<Person>;
let p: Person;
....
}
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4b1fab2d4f2188c8d50fd21762ad126c
Given the following program:
struct Data {
pub items: Vec<&'static str>,
}
trait Generator {
fn append(&mut self, s: &str) {
self.output().push_str(s);
}
fn data(&self) -> &Data;
fn generate_items(&mut self) {
for item in self.data().items.iter() {
match *item {
"foo" => self.append("it was foo\n"),
_ => self.append("it was something else\n"),
}
}
}
fn output(&mut self) -> &mut String;
}
struct MyGenerator<'a> {
data: &'a Data,
output: String,
}
impl<'a> MyGenerator<'a> {
fn generate(mut self) -> String {
self.generate_items();
self.output
}
}
impl<'a> Generator for MyGenerator<'a> {
fn data(&self) -> &Data {
self.data
}
fn output(&mut self) -> &mut String {
&mut self.output
}
}
fn main() {
let data = Data {
items: vec!["foo", "bar", "baz"],
};
let generator = MyGenerator {
data: &data,
output: String::new(),
};
let output = generator.generate();
println!("{}", output);
}
The following errors are produced trying to compile it:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:15:26
|
13 | for item in self.data().items.iter() {
| ---- - immutable borrow ends here
| |
| immutable borrow occurs here
14 | match *item {
15 | "foo" => self.append("it was foo\n"),
| ^^^^ mutable borrow occurs here
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:16:22
|
13 | for item in self.data().items.iter() {
| ---- - immutable borrow ends here
| |
| immutable borrow occurs here
...
16 | _ => self.append("it was something else\n"),
| ^^^^ mutable borrow occurs here
What is the proper way to structure the code so that the mutable field output can be written to while iterating over the immutable field data? Assume the indirection through the Generator trait is being used to share similar logic with other structs, so accessing MyStruct's fields from the trait's default method implementations need to be done through accessor methods like this.
This is a common issue in Rust; the typical way of solving it is the replace dance. This involves making more of the data and methods use mutable references:
struct Data {
pub items: Vec<&'static str>,
}
trait Generator {
fn append(&mut self, s: &str) {
self.output().push_str(s);
}
fn data(&mut self) -> &mut Data;
fn generate_items(&mut self) {
// Take the data. The borrow on self ends after this statement.
let data = std::mem::replace(self.data(), Data { items: vec![] });
// Iterate over the local version. Now append can borrow all it wants.
for item in data.items.iter() {
match *item {
"foo" => self.append("it was foo\n"),
_ => self.append("it was something else\n"),
}
}
// Put the data back where it belongs.
std::mem::replace(self.data(), data);
}
fn output(&mut self) -> &mut String;
}
struct MyGenerator<'a> {
data: &'a mut Data,
output: String,
}
impl<'a> MyGenerator<'a> {
fn generate(mut self) -> String {
self.generate_items();
self.output
}
}
impl<'a> Generator for MyGenerator<'a> {
fn data(&mut self) -> &mut Data {
self.data
}
fn output(&mut self) -> &mut String {
&mut self.output
}
}
fn main() {
let mut data = Data {
items: vec!["foo", "bar", "baz"],
};
let generator = MyGenerator {
data: &mut data,
output: String::new(),
};
let output = generator.generate();
println!("{}", output);
}
The thing to realize is that the compiler is right to complain. Imagine if calling output() had the side effect of mutating the thing that is referenced by the return value of data() Then the iterator you're using in the loop could get invalidated. Your trait functions have the implicit contract that they don't do anything like that, but there is no way of checking this. So the only thing you can do is temporarily assume full control over the data, by taking it out.
Of course, this pattern breaks unwind safety; a panic in the loop will leave the data moved out.
Assume the indirection through the Generator trait is being used to share similar logic with other structs, so accessing MyStruct's fields from the trait's default method implementations need to be done through accessor methods like this.
Then it's impossible.
The compiler recognizes access to different fields when it sees such fields directly; it does not break abstraction boundaries to peek inside the functions called.
There have been discussions about adding attributes on the methods to specifically mention which field is accessed by which method:
the compiler would enforce that a method does not touch any field NOT mentioned in the attribute
the compiler could then use the knowledge that said method only operates on a subset of the fields
however... this is for non-virtual methods.
For a trait this gets significantly more complicated because a trait does not have fields, and each implementer may have a different set of fields!
So now what?
You will need to change your code:
you can split the trait in two, and require two objects (one to iterate, one to mutate)
you can "hide" the mutability of the append method, forcing users to use interior mutability
...
You can use RefCell:
RefCell uses Rust's lifetimes to implement 'dynamic borrowing', a
process whereby one can claim temporary, exclusive, mutable access to
the inner value. Borrows for RefCells are tracked 'at runtime',
unlike Rust's native reference types which are entirely tracked
statically, at compile time. Because RefCell borrows are dynamic it
is possible to attempt to borrow a value that is already mutably
borrowed; when this happens it results in thread panic.
use std::cell::{RefCell, RefMut};
struct Data {
pub items: Vec<&'static str>,
}
trait Generator {
fn append(&self, s: &str) {
self.output().push_str(s);
}
fn data(&self) -> &Data;
fn generate_items(&self) {
for item in self.data().items.iter() {
match *item {
"foo" => self.append("it was foo\n"),
_ => self.append("it was something else\n"),
}
}
}
fn output(&self) -> RefMut<String>;
}
struct MyGenerator<'a> {
data: &'a Data,
output: RefCell<String>,
}
impl<'a> MyGenerator<'a> {
fn generate(self) -> String {
self.generate_items();
self.output.into_inner()
}
}
impl<'a> Generator for MyGenerator<'a> {
fn data(&self) -> &Data {
self.data
}
fn output(&self) -> RefMut<String> {
self.output.borrow_mut()
}
}
fn main() {
let data = Data {
items: vec!["foo", "bar", "baz"],
};
let generator = MyGenerator {
data: &data,
output: RefCell::new(String::new()),
};
let output = generator.generate();
println!("{}", output);
}
Rust playground