This question already has answers here:
Linking the lifetimes of self and a reference in method
(1 answer)
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
(2 answers)
Closed 5 years ago.
I am trying to get a mutable borrow inside a loop, and I cannot get it to work. I've tried all the possible guards, raw pointers, everything.
struct Test<'a> {
a: &'a str,
}
impl<'a> Test<'a> {
pub fn new() -> Self {
Test { a: &mut "test" }
}
pub fn dostuff(&'a mut self) {
self.a = "test";
}
pub fn fixme(&'a mut self) {
let mut i = 0;
while i < 10 {
self.dostuff();
i += 1;
}
}
}
fn main() {
let mut test = Test::new();
test.fixme();
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:19:13
|
19 | self.dostuff();
| ^^^^ mutable borrow starts here in previous iteration of loop
...
22 | }
| - mutable borrow ends here
Rust Playground example code
I cannot manage to figure how to solve this. I need the fix to still keep the function signatures the same. My code is a lot more complex, but this snippet strips it down to the bare minimum.
Here is the complete code of what I'm trying to solve.
When you write fn dostuff(&'a mut self) you are enforcing that the reference to self must live at least as long as the lifetime 'a. But it's the same 'a as you have used in the definition of the Test struct. This means that callers of dostuff have to lend self for the entire lifetime of test. After dostuff() has been called once, self is now borrowed and the borrow doesn't finish until test is dropped. By definition, you can only call that function once, so you cannot call it in a loop.
I need the fix to still keep the function signatures the same
So, you should now understand that this is an impossible requirement. You can have either the function signature as it is, or you can call it in a loop. You can't have both.
Related
This question already has answers here:
Why does this mutable borrow live beyond its scope?
(2 answers)
Closed 8 months ago.
I'd like to mutably borrow a hash map on every iteration of a loop.
I have the following hash map, function, and loop:
use std::collections::HashMap;
fn func<'a>(hash_map: &'a mut HashMap<&'a str, String>) {
unimplimented!();
}
fn loop() {
let mut hash_map = HashMap::new();
let mut i = 0;
while i < 10 {
func(&mut hash_map);
i += 1;
}
}
This will produce the following error on the func(&mut hash_map); line:
cannot borrow `hash_map` as mutable more than once at a time
`hash_map` was mutably borrowed here in the previous iteration of the looprustc(E0499)
main.rs(62, 25): `hash_map` was mutably borrowed here in the previous iteration of the loop
How can I refactor this to be able to mutably borrow the hash map on every iteration of the loop?
I believe I understand Rust's ownership rules enough to understand why this error is happening, just not well enough to fix it.
Note: I know there are better ways to write a loop in Rust, just wanted a very simple loop for this example.
Looks like I was using an unneeded lifetime in the function argument type definition. Instead of hash_map: &'a mut HashMap<&'a str, String>, I could just use hash_map: &mut HashMap<&'a str, String>.
The following code works for me.
use std::collections::HashMap;
use external::func;
fn func<'a>(hash_map: &mut HashMap<&'a str, String>) {
unimplimented!();
}
fn loop() {
let mut hash_map = HashMap::new();
let mut i = 0;
while i < 10 {
func(&mut hash_map);
i += 1;
}
}
This question already has answers here:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Rust borrow mutable self inside match expression
(1 answer)
How can I implement a fetch-cached-or-load operation in Rust?
(1 answer)
Confused about borrowing error in struct method
(1 answer)
Retrieve a mutable reference to a tree value
(1 answer)
Closed 1 year ago.
I'm trying to write some code which unwraps an Option<&mut T> and provides an error message in the panic, however the error message itself comes from the type I'm mutably borrowing for the Option<&mut T>.
Contrived example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d938c198418f346d7ffd570cda4268a4
struct Foo {
bar: Bar,
}
struct Bar {
value: String,
error: String,
}
impl Bar {
fn get_value(&mut self) -> Option<&mut String> {
if self.error.len() > 0 {
None
} else {
Some(&mut self.value)
}
}
}
impl Foo {
fn get_value_or_panic_with_error(&mut self) -> &mut String {
match self.bar.get_value() {
Some(reference) => reference,
None => panic!("{:?}", self.bar.error)
}
}
}
fn main() {
(Foo {
bar: Bar {
value: "a".to_owned(),
error: "".to_owned(),
}
}).get_value_or_panic_with_error();
}
I can understand why the borrow checker doesn't like this because it sees me taking a mutable borrow to get my Option<&mut String> and then taking an immutable borrow on the same thing, however I can't seem to find any way to end the mutable borrow early for the None case as far as the borrow checker is concerned. I've tried dropping the Option if it's None before making the immutable borrow but the borrow checker still complains with the same error.
This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 2 years ago.
In this simplified code, I have two important structs: Owner takes ownership of an object, adds it to a Vec, and returns a reference to it; RefKeeper just holds references to objects in a Vec. Owner also has a RefKeeper.
struct Foo(i32);
struct Owner<'o> {
list: Vec<Foo>,
refkeeper: RefKeeper<'o>,
}
impl<'o> Owner<'o> {
pub fn new() -> Self {
Self {
list: Vec::new(),
refkeeper: RefKeeper::new(),
}
}
pub fn add(&mut self, me: Foo) -> &Foo {
self.list.push(me);
return self.list.last().unwrap();
}
pub fn add_ref(&mut self, me: &'o Foo) {
self.refkeeper.add(me);
}
}
struct RefKeeper<'ro> {
list: Vec<&'ro Foo>,
}
impl<'ro> RefKeeper<'ro> {
pub fn new() -> Self {
Self { list: Vec::new() }
}
pub fn add(&mut self, me: &'ro Foo) {
self.list.push(me);
}
}
fn main() {
let mut owner = Owner::new();
let a1 = Foo(1);
let a1_ref = owner.add(a1);
// this variant doesn't work
owner.add_ref(a1_ref);
// let mut refkeeper = RefKeeper::new();
// refkeeper.add(a1_ref);
// let a2 = Foo(2);
// owner.add_ref(&a2);
}
Two variants work: if I make RefKeeper externally, I can store the ref returned by Owner::add; on the other hand, if I make a new object (a2), I can store &a2 in owner.refkeeper with no problem. Why does the other variant give me this error?
error[E0499]: cannot borrow `owner` as mutable more than once at a time
--> src/main.rs:46:5
|
43 | let a1_ref = owner.add(a1);
| ----- first mutable borrow occurs here
...
46 | owner.add_ref(a1_ref);
| ^^^^^ ------ first borrow later used here
| |
| second mutable borrow occurs here
Is there something fundamentally wrong with this pattern? I'm under the impression that there should be no issue with lifetimes because all the borrows are being used in the same object.
Its because Owner::add returns a reference that is bound to the lifetime of &mut self. So as long as the return value exists (a1_ref) then the &mut self reference does too. So calling add_ref fails because it requires another mut self reference of that same instance.
You can either have one mutable reference, or many immutable references.
The reason calling refkeeper.add and then owner.add_ref is not giving you the same issue is because adding to refkeeper does not require another reference to owner.
You might want to look at std::rc::Rc.
This question already has an answer here:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Closed 3 years ago.
This doesn't make much sense because it returns the same thing regardless of the if let, but it is a concise example of the problem that I am running into:
struct Data {
value: Option<i32>,
}
impl Data {
fn get(&mut self) -> Option<&mut i32> {
if let Some(val) = &mut self.value {
return Some(val);
}
return self.value.as_mut();
}
}
This code produces the error:
error[E0499]: cannot borrow `self.value` as mutable more than once at a time
--> src/lib.rs:11:16
|
6 | fn get(&mut self) -> Option<&mut i32> {
| - let's call the lifetime of this reference `'1`
7 | if let Some(val) = &mut self.value {
| --------------- first mutable borrow occurs here
8 | return Some(val);
| --------- returning this value requires that `self.value` is borrowed for `'1`
...
11 | return self.value.as_mut();
| ^^^^^^^^^^ second mutable borrow occurs here
I don't understand why this is a second mutable borrow when the first one goes out of scope before the second one will ever occur.
The val variable is not in scope after the if let, so how is this a second borrow? The first borrow should have already been released.
Just to be completely sure, I even surrounded the if let with another block:
{
if let Some(val) = &mut self.value {
return Some(val);
}
}
return self.value.as_mut();
This produced the same error. What is going on here?
The lifetime of 'a encompasses the entire function body because the return value needs to borrow self. Hence, the first borrow's scope extends past the if expression and into the entire function body.
Non Lexical Lifetimes were intended to fix this issue by reducing the scope of the first borrow to only include the if expression. You can see this in effect by moving the borrowed value into a local variable (playground):
fn get(&mut self) -> Option<&mut i32> {
let value = &mut self.value;
if let Some(val) = value {
return Some(val);
}
return value.as_mut();
}
However, the support for conditionally returning values was removed because it took too much compilation time. This feature is still being worked on and can be enabled with the -Zpolonius flag:
RUSTFLAGS="-Zpolonius" cargo +nightly build
With which, the original code compiles fine.
This question already has answers here:
Mutably borrow one struct field while borrowing another in a closure
(2 answers)
Closed 5 years ago.
This snippet
use std::collections::HashMap;
struct Foo {
local_ids: HashMap<i32, i32>,
last_id: i32,
}
impl Foo {
fn foo(&mut self, external_id: i32) {
let id = self.local_ids
.entry(external_id)
.or_insert_with(||{self.last_id += 1; self.last_id});
}
}
Doesn't work because we can't borrow self twice
error: closure requires unique access to `self` but `self.local_ids` is already borrowed [E0500]
Is this possible to fix without a second key lookup?
This is very similar to Rust: HashMap borrow issue when trying to implement find or insert, but the API has changed substantially.
The find_with_or_insert_with answer from above doesn't appear to map to the current api.
The problem is that the closure captures self, whereas it only needs to capture a mutable reference to the last_id field.
Rust allows us to take independent mutable borrows on distinct fields, so we can use that to our advantage and pass a mutable reference to the last_id field to the closure.
use std::collections::HashMap;
struct Foo {
local_ids: HashMap<i32, i32>,
last_id: i32,
}
impl Foo {
fn foo(&mut self, external_id: i32) {
let last_id = &mut self.last_id;
let id = self.local_ids
.entry(external_id)
.or_insert_with(|| { *last_id += 1; *last_id });
}
}
When we use the expression self.last_id in the closure, the closure captures self directly, but Rust doesn't realize that the borrows are independent, so we need to be more explicit.