How to call a method while iterating in Rust - rust

Appologies if this is very simple. I'm learning rust and getting used to the strange borrowing system. Usually, you can get the desired behavior just by changing the syntax of your method calls, however, in this case, there seems to be now way.
A simplified version of my code is this: EventPump if from SDL.
struct Example {
pump: EventPump
}
impl Example {
fn method(&mut self) {
for event in pump.poll_iter() {
self.other_method();
}
}
fn other_method(&self) {
}
}
However, I am getting the following error:
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\game.rs:53:67
|
30 | for event in self.pump.poll_iter();
| ---------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
53 | self.other_method();
| ^^^^ immutable borrow occurs here
There is probably some proper way to do this so my struct can maintain ownership of itself, but I have not been able to find it.
I have tried the following:
Turn it into a while loop with explicit while let event = iterator.next(), same error
Making the function mutable, the error now says that no two mutable references are allowed either. I guess the entire "immutability" part of the error message is actually irrelevant.
I could perhaps copy the entire contents of the iterable into a vector or such, but that would defeat the purpose of a iterator, and what if the iterator is not finite? There has to be a better way right...
If someone with more rust experience could help me out it would be much appreciated.

If you want an attribute of a struct to be mutable when there is an immutable reference of a struct in the same block, you'll need RefCell. This is called interior mutability.
If an interior mutability of struct Example is desired, then you will need a RefCell.
use sdl2::{EventPump};
struct Example {
pump: RefCell<EventPump> // wrap in RefCell
}
impl Example {
// you have to decide whether you want a mutable or immutable chained methods
// i.e. method and other_method should be of same mutability because
// other method is called in method
fn method(&self) {
// borrow a mutable reference of pump inside a method with immutable self
let mut pump = self.pump.borrow_mut();
for event in pump.poll_iter() {
self.other_method();
}
}
fn other_method(&self) {
}
}

If you have a pattern like that:
fn method(&mut self) {
for item in self.some_iterator_that_borrow_mut() {
self.other_method();
}
}
The borrow rule that states exactly one mutable reference is broken:
there are one mutable and one immutable reference to self.
To avoid the double reference problem consume the iterator and collect the items into
a temporary collection, for example into a Vec:
impl Example {
fn method(&mut self) {
for event in self.pump.poll_iter().collect::<Vec<_>>(); {
self.other_method();
}
}
fn other_method(&self) {}
}

Related

Cannot borrow `*self` as mutable because it is also borrowed as immutable in Match statement

Apologies, since this seems quite a popular question. I went through a bunch of examples.
How do you borrow a mutable reference during a match? - the solution is not applicable since the get_mut(&0).unwrap() is not available for the self.head object.
Mutable borrow followed by immutable borrow (cannot borrow as immutable because it is also borrowed as mutable) - doesn't provide much insight and redirects to Cannot borrow as mutable because it is also borrowed as immutable. This example does provide valuable learning that there can't be an immutable reference and then a mutable reference in a multi-line statement, but it doesn't still cover the case on a match statement.
Why does refactoring by extracting a method trigger a borrow checker error? - is also closely related, but doesn't handle the specific requirement of the match statement. Again, perhaps obvious to someone experienced with Rust but not to me.
Hence my doubt:
use std::collections::HashMap;
#[derive(Debug)]
struct Node {
word: String,
next: Option<HashMap<char, Node>>,
}
impl Node {
fn new(word: String) -> Self {
Node {
word,
next: None,
}
}
}
#[derive(Debug)]
struct WordDictionary {
head: Option<Node>,
}
impl WordDictionary {
fn new() -> Self {
WordDictionary {
head: None,
}
}
fn add_word(&mut self, word: String) {
match &self.head { // Issue here
None => { /* Do something */ }
Some(nd) => {
self.iterate(nd, word, 0); // And here
}
}
}
fn iterate(&mut self, _parent_node: &Node, _word: String, _idx: usize) {
// Do something
}
}
#[allow(non_snake_case)]
fn main() {
{
let mut wordDictionary = WordDictionary::new();
wordDictionary.add_word("bad".to_string());
println!("{:?}", wordDictionary);
}
}
Gives the following error:
⣿
Execution
Close
Standard Error
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:34:17
|
31 | match &self.head {
| ---------- immutable borrow occurs here
...
34 | self.iterate(nd, word, 0);
| ^^^^^-------^^^^^^^^^^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
Playground
It would be great if someone can provide insight into this specific example or help point another answered example.
Thank you!
First of all, I'm not sure that your iterate function signature is possible. Explanation: your function takes one mutable and one immutable reference at the same time. In Rust, this is not possible. You can have only one mutable or many immutable references.
Because the iteration function has &mut self I suppose that you want to modify smth during the execution. To do that, only one &mut Node will be enough. Like here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c962831b569768f05599b99cdff597bd

Rust multiple mutable borrows are not allowed ONLY when lifetime is stated [duplicate]

I've encountered a confusing error about the use of a mutable and immutable borrow at the same time, after I expect the mutable borrow to end. I've done a lot of research on similar questions (1, 2, 3, 4, 5) which has led me to believe my problem has something to do with lexical lifetimes (though turning on the NLL feature and compiling on nightly doesn't change the result), I just have no idea what; my situation doesn't seem to fit into any of the scenarios of the other questions.
pub enum Chain<'a> {
Root {
value: String,
},
Child {
parent: &'a mut Chain<'a>,
},
}
impl Chain<'_> {
pub fn get(&self) -> &String {
match self {
Chain::Root { ref value } => value,
Chain::Child { ref parent } => parent.get(),
}
}
pub fn get_mut(&mut self) -> &mut String {
match self {
Chain::Root { ref mut value } => value,
Chain::Child { ref mut parent } => parent.get_mut(),
}
}
}
#[test]
fn test() {
let mut root = Chain::Root { value: "foo".to_string() };
{
let mut child = Chain::Child { parent: &mut root };
*child.get_mut() = "bar".to_string();
} // I expect child's borrow to go out of scope here
assert_eq!("bar".to_string(), *root.get());
}
playground
The error is:
error[E0502]: cannot borrow `root` as immutable because it is also borrowed as mutable
--> example.rs:36:36
|
31 | let mut child = Chain::Child { parent: &mut root };
| --------- mutable borrow occurs here
...
36 | assert_eq!("bar".to_string(), *root.get());
| ^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
I understand why an immutable borrow happens there, but I do not understand how a mutable borrow is used there. How can both be used at the same place? I'm hoping someone can explain what is happening and how I can avoid it.
In short, &'a mut Chain<'a> is extremely limiting and pervasive.
For an immutable reference &T<'a>, the compiler is allowed to shorten the lifetime of 'a when necessary to match other lifetimes or as part of NLL (this is not always the case, it depends on what T is). However, it cannot do so for mutable references &mut T<'a>, otherwise you could assign it a value with a shorter lifetime.
So when the compiler tries to reconcile the lifetimes when the reference and the parameter are linked &'a mut T<'a>, the lifetime of the reference is conceptually expanded to match the lifetime of the parameter. Which essentially means you've created a mutable borrow that will never be released.
Applying that knowledge to your question: creating a reference-based hierarchy is really only possible if the nested values are covariant over their lifetimes. Which excludes:
mutable references
trait objects
structs with interior mutability
Refer to these variations on the playground to see how these don't quite work as expected.
See also:
Why does linking lifetimes matter only with mutable references?
How do I implement the Chain of Responsibility pattern using a chain of trait objects?
What are the differences when getting an immutable reference from a mutable reference with self-linked lifetimes?
For fun, I'll include a case where the Rust standard library does this sort of thing on purpose. The signature of std::thread::scope looks like:
pub fn scope<'env, F, T>(f: F) -> T
where
F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T
The Scope that is provided to the user-defined function intentionally has its lifetimes tied in a knot to ensure it is only used in intended ways. This is not always the case since structs may be covariant or contravariant over their generic types, but Scope is defined to be invariant. Also, the only function that can be called on it is .spawn() which intentionally takes &'scope self as the self-parameter as well, ensuring that the reference does not have a shorter lifetime than what is given by scope.
Internally, the standard library contains this documentation (source):
Invariance over 'scope, to make sure 'scope cannot shrink, which is necessary for soundness.
Without invariance, this would compile fine but be unsound:
std::thread::scope(|s| {
s.spawn(|| {
let a = String::from("abcd");
s.spawn(|| println!("{a:?}")); // might run after `a` is dropped
});
});
Even if the lifetime of the reference is invariant with respect to itself, this still avoids many problems above because it uses an immutable reference and interior-mutability. If the parameter to .spawn() required &'scope mut self, then this would not work and run into the same problems above when trying to spawn more than one thread.
The issue isn't lexical lifetimes, and adding an explicit drop won't change the error. The issue is with the &'a mut Chain<'a>- that forces root to be borrowed for its entire life, rendering it useless after the borrow is dropped. As per the comment below, doing this with lifetimes is basically impossible. I would suggest using a box instead. Changing the struct to
pub enum Chain{
Root {
value: String,
},
Child {
parent: Box<Chain>,
},
}
and adjusting the other methods as necesary. Alternatively, using an Rc<RefCell<Chain>> if you want the original to remain usable without consuming self.

How to fix ".. was mutably borrowed here in the previous iteration of the loop" in Rust?

I have to iterate on keys, find the value in HashMap by key, possibly do some heavy computation in the found struct as a value (lazy => mutate the struct) and cached return it in Rust.
I'm getting the following error message:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:25:26
|
23 | fn it(&mut self) -> Option<&Box<Calculation>> {
| - let's call the lifetime of this reference `'1`
24 | for key in vec!["1","2","3"] {
25 | let result = self.find(&key.to_owned());
| ^^^^ `*self` was mutably borrowed here in the previous iteration of the loop
...
28 | return result
| ------ returning this value requires that `*self` is borrowed for `'1`
Here is the code in playground.
use std::collections::HashMap;
struct Calculation {
value: Option<i32>
}
struct Struct {
items: HashMap<String, Box<Calculation>> // cache
}
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None // find, create, and/or calculate items
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
let result = self.find(&key.to_owned());
if result.is_some() {
return result
}
}
None
}
}
I can't avoid the loop as I have to check multiple keys
I have to make it mutable (self and the structure) as the possible calculation changes it
Any suggestion on how to change the design (as Rust forces to think in a bit different way that makes sense) or work around it?
PS. There are some other issues with the code, but let's split the problems and solve this one first.
You can't do caching with exclusive access. You can't treat Rust references like general-purpose pointers (BTW: &String and &Box<T> are double indirection, and very unidiomatic in Rust. Use &str or &T for temporary borrows).
&mut self means not just mutable, but exclusive and mutable, so your cache supports returning only one item, because the reference it returns has to keep self "locked" for as long as it exists.
You need to convince the borrow checker that the thing that find returns won't suddenly disappear next time you call it. Currently there's no such guarantee, because the interface doesn't stop you from calling e.g. items.clear() (borrow checker checks what function's interface allows, not what function actually does).
You can do that either by using Rc, or using a crate that implements a memory pool/arena.
struct Struct {
items: HashMap<String, Rc<Calculation>>,
}
fn find(&mut self, key: &str) -> Rc<Calculation>
This way if you clone the Rc, it will live for as long as it needs, independently of the cache.
You can also make it nicer with interior mutability.
struct Struct {
items: RefCell<HashMap<…
}
This will allow your memoizing find method to use a shared borrow instead of an exclusive one:
fn find(&self, key: &str) -> …
which is much easier to work with for the callers of the method.
Probably not the cleanest way to do that, but it compiles. The idea is not to store the value found in a temporary result, to avoid aliasing: if you store the result, self is kept borrowed.
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
if self.find(&key.to_owned()).is_some() {
return self.find(&key.to_owned());
}
}
None
}
}
I had similar issues, and I found a workaround by turning the for loop into a fold, which convinced the compiler that self was not mutably borrowed twice.
It works without using interior mutability or duplicated function call; the only downside is that if the result was found early, it will not short-circuit but continue iterating until the end.
Before:
for key in vec!["1","2","3"] {
let result = self.find(&key.to_owned());
if result.is_some() {
return result
}
}
After:
vec!["1", "2,", "3"]
.iter()
.fold(None, |result, key| match result {
Some(result) => Some(result),
None => self.find(&key.to_string())
})
Working playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=92bc73e4bac556ce163e0790c7d3f154

Why does this mutable borrow live beyond its scope?

I've encountered a confusing error about the use of a mutable and immutable borrow at the same time, after I expect the mutable borrow to end. I've done a lot of research on similar questions (1, 2, 3, 4, 5) which has led me to believe my problem has something to do with lexical lifetimes (though turning on the NLL feature and compiling on nightly doesn't change the result), I just have no idea what; my situation doesn't seem to fit into any of the scenarios of the other questions.
pub enum Chain<'a> {
Root {
value: String,
},
Child {
parent: &'a mut Chain<'a>,
},
}
impl Chain<'_> {
pub fn get(&self) -> &String {
match self {
Chain::Root { ref value } => value,
Chain::Child { ref parent } => parent.get(),
}
}
pub fn get_mut(&mut self) -> &mut String {
match self {
Chain::Root { ref mut value } => value,
Chain::Child { ref mut parent } => parent.get_mut(),
}
}
}
#[test]
fn test() {
let mut root = Chain::Root { value: "foo".to_string() };
{
let mut child = Chain::Child { parent: &mut root };
*child.get_mut() = "bar".to_string();
} // I expect child's borrow to go out of scope here
assert_eq!("bar".to_string(), *root.get());
}
playground
The error is:
error[E0502]: cannot borrow `root` as immutable because it is also borrowed as mutable
--> example.rs:36:36
|
31 | let mut child = Chain::Child { parent: &mut root };
| --------- mutable borrow occurs here
...
36 | assert_eq!("bar".to_string(), *root.get());
| ^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
I understand why an immutable borrow happens there, but I do not understand how a mutable borrow is used there. How can both be used at the same place? I'm hoping someone can explain what is happening and how I can avoid it.
In short, &'a mut Chain<'a> is extremely limiting and pervasive.
For an immutable reference &T<'a>, the compiler is allowed to shorten the lifetime of 'a when necessary to match other lifetimes or as part of NLL (this is not always the case, it depends on what T is). However, it cannot do so for mutable references &mut T<'a>, otherwise you could assign it a value with a shorter lifetime.
So when the compiler tries to reconcile the lifetimes when the reference and the parameter are linked &'a mut T<'a>, the lifetime of the reference is conceptually expanded to match the lifetime of the parameter. Which essentially means you've created a mutable borrow that will never be released.
Applying that knowledge to your question: creating a reference-based hierarchy is really only possible if the nested values are covariant over their lifetimes. Which excludes:
mutable references
trait objects
structs with interior mutability
Refer to these variations on the playground to see how these don't quite work as expected.
See also:
Why does linking lifetimes matter only with mutable references?
How do I implement the Chain of Responsibility pattern using a chain of trait objects?
What are the differences when getting an immutable reference from a mutable reference with self-linked lifetimes?
For fun, I'll include a case where the Rust standard library does this sort of thing on purpose. The signature of std::thread::scope looks like:
pub fn scope<'env, F, T>(f: F) -> T
where
F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T
The Scope that is provided to the user-defined function intentionally has its lifetimes tied in a knot to ensure it is only used in intended ways. This is not always the case since structs may be covariant or contravariant over their generic types, but Scope is defined to be invariant. Also, the only function that can be called on it is .spawn() which intentionally takes &'scope self as the self-parameter as well, ensuring that the reference does not have a shorter lifetime than what is given by scope.
Internally, the standard library contains this documentation (source):
Invariance over 'scope, to make sure 'scope cannot shrink, which is necessary for soundness.
Without invariance, this would compile fine but be unsound:
std::thread::scope(|s| {
s.spawn(|| {
let a = String::from("abcd");
s.spawn(|| println!("{a:?}")); // might run after `a` is dropped
});
});
Even if the lifetime of the reference is invariant with respect to itself, this still avoids many problems above because it uses an immutable reference and interior-mutability. If the parameter to .spawn() required &'scope mut self, then this would not work and run into the same problems above when trying to spawn more than one thread.
The issue isn't lexical lifetimes, and adding an explicit drop won't change the error. The issue is with the &'a mut Chain<'a>- that forces root to be borrowed for its entire life, rendering it useless after the borrow is dropped. As per the comment below, doing this with lifetimes is basically impossible. I would suggest using a box instead. Changing the struct to
pub enum Chain{
Root {
value: String,
},
Child {
parent: Box<Chain>,
},
}
and adjusting the other methods as necesary. Alternatively, using an Rc<RefCell<Chain>> if you want the original to remain usable without consuming self.

How to avoid mutex borrowing problems when using it's guard

I want my method of struct to perform in a synchronized way. I wanted to do this by using Mutex (Playground):
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
map: BTreeMap<String, String>,
mutex: Mutex<()>,
}
impl A {
pub fn new() -> A {
A {
map: BTreeMap::new(),
mutex: Mutex::new(()),
}
}
}
impl A {
fn synchronized_call(&mut self) {
let mutex_guard_res = self.mutex.try_lock();
if mutex_guard_res.is_err() {
return
}
let mut _mutex_guard = mutex_guard_res.unwrap(); // safe because of check above
let mut lambda = |text: String| {
let _ = self.map.insert("hello".to_owned(),
"d".to_owned());
};
lambda("dd".to_owned());
}
}
Error message:
error[E0500]: closure requires unique access to `self` but `self.mutex` is already borrowed
--> <anon>:23:26
|
18 | let mutex_guard_res = self.mutex.try_lock();
| ---------- borrow occurs here
...
23 | let mut lambda = |text: String| {
| ^^^^^^^^^^^^^^ closure construction occurs here
24 | if let Some(m) = self.map.get(&text) {
| ---- borrow occurs due to use of `self` in closure
...
31 | }
| - borrow ends here
As I understand when we borrow anything from the struct we are unable to use other struct's fields till our borrow is finished. But how can I do method synchronization then?
The closure needs a mutable reference to the self.map in order to insert something into it. But closure capturing works with whole bindings only. This means, that if you say self.map, the closure attempts to capture self, not self.map. And self can't be mutably borrowed/captured, because parts of self are already immutably borrowed.
We can solve this closure-capturing problem by introducing a new binding for the map alone such that the closure is able to capture it (Playground):
let mm = &mut self.map;
let mut lambda = |text: String| {
let _ = mm.insert("hello".to_owned(), text);
};
lambda("dd".to_owned());
However, there is something you overlooked: since synchronized_call() accepts &mut self, you don't need the mutex! Why? Mutable references are also called exclusive references, because the compiler can assure at compile time that there is only one such mutable reference at any given time.
Therefore you statically know, that there is at most one instance of synchronized_call() running on one specific object at any given time, if the function is not recursive (calls itself).
If you have mutable access to a mutex, you know that the mutex is unlocked. See the Mutex::get_mut() method for more explanation. Isn't that amazing?
Rust mutexes do not work the way you are trying to use them. In Rust, a mutex protects specific data relying on the borrow-checking mechanism used elsewhere in the language. As a consequence, declaring a field Mutex<()> doesn't make sense, because it is protecting read-write access to the () unit object that has no values to mutate.
As Lukas explained, your call_synchronized as declared doesn't need to do synchronization because its signature already requests an exclusive (mutable) reference to self, which prevents it from being invoked from multiple threads on the same object. In other words, you need to change the signature of call_synchronized because the current one does not match the functionality it is intended to provide.
call_synchronized needs to accept a shared reference to self, which will signal to Rust that it can be called from multiple threads in the first place. Inside call_synchronized a call to Mutex::lock will simultaneously lock the mutex and provide a mutable reference to the underlying data, carefully scoped so that the lock is held for the duration of the reference:
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
synced_map: Mutex<BTreeMap<String, String>>,
}
impl A {
pub fn new() -> A {
A {
synced_map: Mutex::new(BTreeMap::new()),
}
}
}
impl A {
fn synchronized_call(&self) {
let mut map = self.synced_map.lock().unwrap();
// omitting the lambda for brevity, but it would also work
// (as long as it refers to map rather than self.map)
map.insert("hello".to_owned(), "d".to_owned());
}
}

Resources