Rust - iterator with mut ref of owner inside [duplicate] - rust

This question already has answers here:
Why does refactoring by extracting a method trigger a borrow checker error?
(2 answers)
Closed 3 years ago.
I struggle with iterator which also mutates other fields of it's owner.
I've re-created a simplified example Playground:
#[derive(PartialEq)]
enum ResourceEnum {
Food,
}
struct Resource {
r#type: ResourceEnum,
amount: u32,
}
trait Building {
fn produce(&self) -> Option<Resource>;
}
struct Farm {}
struct City {
buildings: Vec<Box<dyn Building>>,
resources: Vec<Resource>,
}
impl City {
fn add_resource(&mut self, received: Option<Resource>) {
if let Some(received) = received {
if let Some(mut res) = self
.resources
.iter_mut()
.find(|r| r.r#type == received.r#type)
{
res.amount += received.amount;
} else {
self.resources.push(received);
}
}
}
}
impl Building for Farm {
fn produce(&self) -> Option<Resource> {
Some(Resource {
r#type: ResourceEnum::Food,
amount: 10,
})
}
}
fn main() {
let mut city = City {
buildings: vec![],
resources: vec![],
};
city.buildings.iter().for_each(|f| {
city.add_resource(f.produce());
});
}
Error:
error[E0502]: cannot borrow `city` as mutable because it is also borrowed as immutable
--> src/main.rs:55:36
|
53 | city.buildings.iter().for_each(|f| {
| -------------- -------- ^^^ mutable borrow occurs here
| | |
| | immutable borrow later used by call
| immutable borrow occurs here
54 | city.add_resource(f.produce());
| ---- second borrow occurs due to use of `city` in closure
What I'm trying to achieve is to have a single struct holding my 'world' -> City, which holds buildings like farms and all it's available resources like food.
At each state update I want to compute harvest from all farms and so on... and add produced resources into City storage, but can't figure out a way without storing all production as a separate Vector and iterating over it once again to just add it into City storage which seems redundant.
I guess I struggle to find a better way to design a structure of my world, but can't think of anything.

What can of course work is to separate the production of resources and adding them to the city. I've modified your Playground to get it to compile:
let mut v:Vec<Option<ResourceEnum>> = city.buildings.iter().map(|f| f.produce()).collect();
v.drain(..).for_each(|r| city.add_resource(r));
But certainly you cannot call a mutable function on City while iterating on the buildings inside the same object.

Related

Store reference of object in field of struct

I have the following struct:
#[derive(Default)]
pub struct AppState {
actors: HashMap<String, ActorValue>,
feature: HashMap<String, FeatureValue>,
}
Actors are registered when running the application upon receiving a network request (i.e., they are inserted into the HashMap). Furthermore, a user can create a new feature for which a certain actor may be required.
pub enum ActorValue {
Automotive(AutomotiveActor),
Power(PowerActor),
}
pub enum FeatureValue {
Automotive(AutomotiveFeature),
// ....
}
pub struct AutomotiveFeature {
pub actor_name: String,
// ... more Actor-related String fields
}
pub struct AutomotiveActor {
name: String,
// ... more String fields
}
So, when creating an instance of AutomotiveFeature I am currently cloning the name of the respective AutomotiveActor instance to populate the actor_name:
let automotive_actor = app_state.actors.iter()
.find(|x| matches!(x.1, ActorValue::Automotive(_)))
.map(|x| match x.1 {
ActorValue::Automotive(p) => Some(p),
_ => None,
})
.flatten();
match automotive_actor {
Some(a) => {
let feature = AutomotiveFeature { actor_name: a.name.clone() };
}
None => {}
}
However, I am essentially keeping redundant info. Ideally, I could just replace all the String fields relating to the actor in the feature with a reference:
pub struct AutomotiveFeature {
pub actor: &AutomotiveActor
}
But I am getting lifetime issues and I don't know how I can annotate them correctly, considering I have two HashMaps.
If I use:
pub struct AutomotiveFeature {
pub actor: &'static AutomotiveActor
}
I get the following errors:
error[E0502]: cannot borrow `*state` as mutable because it is also borrowed as immutable
--> crates/code/src/my_code.rs:146:13
|
38 | let automotive_actor: Option<&AutomotiveActor> = app_state
| __________________________________________________-
39 | | .actors()
| |_____________________________- immutable borrow occurs here
...
43 | ActorValue::Automotive(p) => Some(p),
| ------- returning this value requires that `*state` is borrowed for `'static`
...
146 | / app_state
147 | | .features_mut()
| |____________________________^ mutable borrow occurs here
error: lifetime may not live long enough
--> crates/code/src/my_code.rs:43:40
|
35 | app_state: &mut AppState,
| - let's call the lifetime of this reference `'1`
...
43 | ActorValue::Automotive(p) => Some(p),
| ^^^^^^^ returning this value requires that `'1` must outlive `'static`
I have already looked at similar post, such as "Store reference of struct in other struct". Unfortunately, I cannot use std::rc::Rc; because I get the error:
`Rc<AutomotiveActor>` cannot be sent between threads safely
I am getting lifetime issues and I don't know how I can annotate them correctly"
Note that you can only explain to the compiler how long something lives. You can't actually make an object live longer by annotating a lifetime. References do not own an object or keep it alive. Rc/Arc actually keep an object alive, so I have a suspicion that this is what you want.
The reason I want to have a reference is that I can then implement methods as part of AutomotiveActor and then directly call automotive_actor.start_car()
I suspect that start_car() modifies the automotive_actor and is therefore a mut fn. This completely renders your initial idea of using references impossible, because you can only ever have one mutable reference to an object.
Rc/Arc also only provide immutable access to the object, but you can combine them with RefCell/Mutex to create interior mutability.
Rc<AutomotiveActor> cannot be sent between threads safely
This makes me assume that your project is multi-threaded and therefore requires thread safety. This means you probably want to use Arc<Mutex>.
This is one possible layout:
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
#[derive(Default)]
pub struct AppState {
actors: HashMap<String, ActorValue>,
feature: HashMap<String, FeatureValue>,
}
pub enum ActorValue {
Automotive(Arc<Mutex<AutomotiveActor>>),
//Power(PowerActor),
}
pub enum FeatureValue {
Automotive(AutomotiveFeature),
// ....
}
pub struct AutomotiveFeature {
pub actor: Arc<Mutex<AutomotiveActor>>,
// ... more Actor-related String fields
}
pub struct AutomotiveActor {
name: String,
// ... more String fields
}
fn main() {
let mut app_state = AppState::default();
let new_actor = Arc::new(Mutex::new(AutomotiveActor {
name: String::from("MyActor"),
}));
app_state.actors.insert(
new_actor.lock().unwrap().name.clone(),
ActorValue::Automotive(Arc::clone(&new_actor)),
);
let automotive_actor = app_state
.actors
.iter()
.find(|x| matches!(x.1, ActorValue::Automotive(_)))
.map(|x| match x.1 {
ActorValue::Automotive(p) => Some(p),
_ => None,
})
.flatten();
match automotive_actor {
Some(a) => {
let feature = AutomotiveFeature {
actor: Arc::clone(a),
};
}
None => {}
}
}

How can I do a mutable borrow after an immutable borrow?

The code
fn play(&self, game: &mut crate::game::Game) {
let player_in_turn: &Player = game.get_player_in_turn();
match player_in_turn.player_kind {
PlayerKind::AI => {
player_in_turn.do_random_move(&mut game);
}
_ => {
panic!("not implemented yet");
}
}
game.status = Status::ExitGame;
}
Where get_player_in_turn is
pub fn get_player_in_turn(&self) -> &Player {
match self.status {
Status::InGame(ig_status) => match ig_status {
InGameStatus::PlayFirst => {
if self.player_a.play_order == PlayOrder::First {
&self.player_a
} else {
&self.player_b
}
}
InGameStatus::PlaySecond => {
if self.player_a.play_order == PlayOrder::Second {
&self.player_a
} else {
&self.player_b
}
}
},
_ => {
panic!("get_player_in_turn called when not in a in-game status");
}
}
}
The compiler is telling me
error[E0502]: cannot borrow `game` as mutable because it is also borrowed as immutable
--> src\game\status\in_game_status.rs:28:47
|
25 | let player_in_turn: &Player = game.get_player_in_turn();
| ------------------------- immutable borrow occurs here
...
28 | player_in_turn.do_random_move(&mut game);
| -------------- ^^^^^^^^^ mutable borrow occurs here
| |
| immutable borrow later used by call
Usually I am able to understand the what and the why of compilers erros
I understand this
let player_in_turn: &Player = game.get_player_in_turn(); : I keep from game a ref to the current player; so I get an immutable ref of kind &Player
Here the game variable is immutably borrowed because of fn signature get_player_in_turn(&self). That's right, I do not want allow modifications to game in the get_player_in_turn, but also I need a ref because I need the player in turn, not a copy, or what else
player_in_turn.do_random_move(&mut game); : The instance of Player now alters the game itself doing its move
And here game should be passed as mutable because it's the goal of do_random_move
Question
I can understand the why of this but not how can I workaround
As you said, you know why this happens. Optimal workaround is to rewrite your code to use less borrowing. So you definitely can't do that if you want to modify some previously borrowed data. But if your do_random_move() function does not change internals of Players, then you can use this design pattern.
The core idea is to split borrowing into parts. Right now you are borrowing full Game structure when calling get_player_in_turn, but you only need 3 fields there: status, player_a, player_b. You can create a new function that takes them as arguments and this will split your borrowing and will allow you to borrow other fields of Game later (probably for do_random_move implementation).
here is example code

Can't find my way arround lifetime and borrowing

This problem is very simple, yet I can't figure out how to implement this in Rust:
I have a TCP server that awaits for new clients connection. Each Client stores it's TCPStream and a UUID and is stored in a ClientHolder struct. This struct implements an update function that will call Client::update for each Client.
The Client::update function looks like this:
pub fn update(&mut self) -> bool {
let mut msg = String::new();
match self.bufreader.read_line(&mut msg) {
Ok(size) => {
if size > 1 {
self.parse(&msg);
}
true
}
Err(_) => {
println!(
"Terminating connection with {}",
self.stream.peer_addr().unwrap()
);
self.stream.shutdown(Shutdown::Both).unwrap();
false
}
}
}
I need the parse function to be able to execute code that'll modify a Client (for example to transfer a command from a client to another). I can't find a way to get a reference to a Client from inside the parse function without triggering borrowing or lifetime errors that I can't fix.
I would really appreciate if someone could point me in the right direction. I've been struggling for two days on this issue and tried many things.
EDIT:
This is an example of what could be parse:
fn parse(&mut self, msg: &String, holder: &ClientHolder) {
let v: Value = serde_json::from_str(&msg).unwrap();
if v["type"] == "init" {
self.set_uuid(v["uuid"].to_string());
}
else {
let uuid = v["uuid"];
let client = holder.get_client(&uuid);
command_service.try_execute(v["type"], client);
}
}
If &ClientHolder is forwarded using update, this is what happens:
Inside ClientHolder, the update function calls Client::update and pass an immutable reference of self. If the client is disconnected, it removes it from the Vec.
pub fn update(&mut self) {
for i in (0..self.clients.len()).rev() {
let client = &mut self.clients[i];
if !client.update(&*self) {
self.clients.swap_remove(i);
}
}
}
The compiler gives me this error:
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\server\client_holder.rs:25:31
|
24 | let client = &mut self.clients[i];
| ------------ mutable borrow occurs here
25 | if !client.update(&*self) {
| ------ ^^^^^^ immutable borrow occurs here
| |
| mutable borrow later used by call
I understand why it does, but couldn't find a solution that works for me.

What is the most idiomatic way of using struct methods that modify the struct's internal state from within a loop? [duplicate]

This question already has answers here:
What do I have to do to solve a "use of moved value" error?
(3 answers)
What types are valid for the `self` parameter of a method?
(2 answers)
Closed 3 years ago.
It seems to be fine to modify a vector on its own, but as soon as it is wrapped in a struct, it can not be mutated by a method on the struct.
I've created a very simplified version of my use case below, in two versions, one with just a vector, and one with a struct.
Why is it that this code is fine:
struct Task {
foo: String,
}
fn main() {
let mut list_of_tasks = Vec::new();
loop {
list_of_tasks.push(Task {
foo: String::from("bar"),
});
}
}
But this is not:
struct Task {
foo: String,
}
struct ListOfTasks(pub Vec<Task>);
impl ListOfTasks {
fn push(mut self, task: Task) {
self.0.push(task);
}
}
fn main() {
let list_of_tasks = ListOfTasks(Vec::new());
loop {
list_of_tasks.push(Task {
foo: String::from("bar"),
});
}
}
The second example fails with:
error[E0382]: use of moved value: `list_of_tasks`
--> src/main.rs:17:9
|
14 | let list_of_tasks = ListOfTasks(Vec::new());
| ------------- move occurs because `list_of_tasks` has type `ListOfTasks`, which does not implement the `Copy` trait
...
17 | list_of_tasks.push(Task {
| ^^^^^^^^^^^^^ value moved here, in previous iteration of loop
I think I'm not understanding something about moving a struct that uses mut self, but can't find any obvious examples online of how to approach this.

Why does calling a method on a mutable reference involve "borrowing"?

I'm learning Rust and I'm trying to cargo-cult this code into compiling:
use std::vec::Vec;
use std::collections::BTreeMap;
struct Occ {
docnum: u64,
weight: f32,
}
struct PostWriter<'a> {
bytes: Vec<u8>,
occurrences: BTreeMap<&'a [u8], Vec<Occ>>,
}
impl<'a> PostWriter<'a> {
fn new() -> PostWriter<'a> {
PostWriter {
bytes: Vec::new(),
occurrences: BTreeMap::new(),
}
}
fn add_occurrence(&'a mut self, term: &[u8], occ: Occ) {
let occurrences = &mut self.occurrences;
match occurrences.get_mut(term) {
Some(x) => x.push(occ),
None => {
// Add the term bytes to the big vector of all terms
let termstart = self.bytes.len();
self.bytes.extend(term);
// Create a new occurrences vector
let occs = vec![occ];
// Take the appended term as a slice to use as a key
// ERROR: cannot borrow `*occurrences` as mutable more than once at a time
occurrences.insert(&self.bytes[termstart..], occs);
}
}
}
}
fn main() {}
I get an error:
error[E0499]: cannot borrow `*occurrences` as mutable more than once at a time
--> src/main.rs:34:17
|
24 | match occurrences.get_mut(term) {
| ----------- first mutable borrow occurs here
...
34 | occurrences.insert(&self.bytes[termstart..], occs);
| ^^^^^^^^^^^ second mutable borrow occurs here
35 | }
36 | }
| - first borrow ends here
I don't understand... I'm just calling a method on a mutable reference, why would that line involve borrowing?
I'm just calling a method on a mutable reference, why would that line involve borrowing?
When you call a method on an object that's going to mutate the object, you can't have any other references to that object outstanding. If you did, your mutation could invalidate those references and leave your program in an inconsistent state. For example, say that you had gotten a value out of your hashmap and then added a new value. Adding the new value hits a magic limit and forces memory to be reallocated, your value now points off to nowhere! When you use that value... bang goes the program!
In this case, it looks like you want to do the relatively common "append or insert if missing" operation. You will want to use entry for that:
use std::collections::BTreeMap;
fn main() {
let mut map = BTreeMap::new();
{
let nicknames = map.entry("joe").or_insert(Vec::new());
nicknames.push("shmoe");
// Using scoping to indicate that we are done with borrowing `nicknames`
// If we didn't, then we couldn't borrow map as
// immutable because we could still change it via `nicknames`
}
println!("{:?}", map)
}
Because you're calling a method that borrows as mutable
I had a similar question yesterday about Hash, until I noticed something in the docs. The docs for BTreeMap show a method signature for insert starting with fn insert(&mut self..
So when you call .insert, you're implicitly asking that function to borrow the BTreeMap as mutable.

Resources