Multiple mutable borrows when using result of a method call [duplicate] - rust

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.

Related

Cannot borrow `b` as mutable more than once at a time without reference return value [duplicate]

This question already has an answer here:
Why is there a borrow of a moved value when calling a method that takes self by value with an argument that also calls a method?
(1 answer)
Closed last year.
The below rust code has compilation error.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
b.add(b.add(10));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> examples/mutable_borrow_at_a_time.rs:10:11
|
10 | b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
Unlike the question Cannot borrow `x` as mutable more than once at a time, add does not return any reference at all.
Unlike the question Borrow errors for multiple borrows, the return type is i32 which has 'static lifetime.
While the following code can be compiled without errors.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
let x = b.add(10);
b.add(x);
}
Anyway it is cumbersome to create a dummy variable x every time for a compound expression.
First there will be a mutable borrow on the outer b.add(...) and then there will be an attempt to make a second mutable borrow on the inner b.add(). That is wonderfully explained & visualized by the compiler in the error message that you pasted:
| b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
This limitation might be removed at some point, but for now, that's how it works.
And for your specific example, as Jmb mentioned, you don't need mut at all, so this will work just fine:
struct Builder;
impl Builder {
pub fn add(&self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let b = Builder;
b.add(b.add(10));
}
It looks like you are attempting to use the builder pattern.
The difficulty stands in passing a &mut on the builder from call to call.
Each step in the chain should rather consume the previous state of the builder and emit a new state (like add() here).
Finally, the last step (build()) consumes the builder for the last time and emits instead the value we intended to build.
You might be worried about the performance cost of these multiple move/consume operations (instead of altering through a &mut), but when enabling optimizations, the compiler is able to look through these calls and can decide to do everything in place: a function only containing Builder::new().add(10).add(20).build() produces mov eax, 30 ret.
struct Builder {
id: i32,
}
impl Builder {
pub fn new() -> Self {
Builder { id: 0 }
}
pub fn add(
mut self,
incr: i32,
) -> Self {
self.id += incr;
self
}
pub fn build(self) -> i32 {
self.id
}
}
fn main() {
let id = Builder::new().add(10).add(20).build();
println!("id={:?}", id);
}

Passing both &mut self and &self to the same function

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());
}

Rust multiple mutable self borrowing from method calls

I am learning Rust. For my first program, I wrote this code to maintain data about a partial ordering:
use std::collections::{HashMap, HashSet};
struct Node {
num_before: usize,
successors: HashSet<String>,
}
impl Node {
fn new() -> Node {
Node {
num_before: 0,
successors: HashSet::new(),
}
}
}
pub struct PartialOrdering {
node: HashMap<String, Node>,
}
impl PartialOrdering {
pub fn new() -> PartialOrdering {
PartialOrdering {
node: HashMap::new(),
}
}
pub fn get_node(&mut self, name: &String) -> &mut Node {
self.node.entry(name.clone()).or_insert_with(Node::new)
}
pub fn add_order(&mut self, before: &String, after: &String) {
let mut before_node = self.get_node(before);
if after != before {
let mut after_node = self.get_node(after);
if before_node.successors.insert(after.clone()) {
after_node.num_before += 1;
}
}
}
}
Compiling this code produces this error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> main.rs:35:25
|
33 | let before_node = self.get_node(before);
| ---- first mutable borrow occurs here
34 | if after != before {
35 | let mut after_node = self.get_node(after);
| ^^^^ second mutable borrow occurs here
36 | if before_node.successors.insert(after.clone()) {
| ---------------------- first borrow later used here
Admittedly I am new to the Rust borrowing rules, but this problem has me stumped. Please tell me what I am doing wrong, and how can I fix it?
The problem is that in Rust it is forbidden to take more than one mutable reference (&mut) to an object at a time (see here for details). Your get_node() takes &mut self and uses it to obtain an &mut Node contained in self (where self is a PartialOrdering). This causes the mutable borrow of self to exist for as long as the value returned by get_node() exists, preventing other calls to get_node(). This means that you can't have before_node: &mut Node and after_node: &mut Node in the same scope, unfortunately.

Lifetime on trait returning iterator

I'm working with a trait requiring a function returning an iterator without consuming the object. The iterator itself returns copies of data values, not references. As the iterator implementation requires a reference to the object it is iterating over, I end up having to declare lots of lifetimes (more than I would have thought necessary, but could not get it to compile otherwise). I then run into trouble with borrow duration - a minimal "working" example is as follows:
pub trait MyTrait<'a> {
type IteratorType: Iterator<Item=u32>;
fn iter(&'a self) -> Self::IteratorType;
fn touch(&'a mut self, value: u32);
}
struct MyStruct {
data: Vec<u32>
}
struct MyIterator<'a> {
structref: &'a MyStruct,
next: usize,
}
impl<'a> Iterator for MyIterator<'a> {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.next < self.structref.data.len() {
self.next += 1;
return Some(self.structref.data[self.next-1]);
} else {
return None;
}
}
}
impl<'a> MyTrait<'a> for MyStruct {
type IteratorType = MyIterator<'a>;
fn iter(&'a self) -> Self::IteratorType {
return MyIterator { structref: &self, next: 0 };
}
fn touch(&'a mut self, value: u32) {
}
}
fn touch_all<'a,T>(obj: &'a mut T) where T: MyTrait<'a> {
let data: Vec<u32> = obj.iter().collect();
for value in data {
obj.touch(value);
}
}
Compiling this gives me the error:
error[E0502]: cannot borrow `*obj` as mutable because it is also borrowed as immutable
|
39 | let data: Vec<u32> = obj.iter().collect();
| --- immutable borrow occurs here
40 | for value in data {
41 | obj.touch(value);
| ^^^ mutable borrow occurs here
42 | }
43 | }
| - immutable borrow ends here
By my limited understanding of lifetimes, I would have thought the immutable borrow only extends to the line where I make it - after all the iterator is consumed and I no longer hold any references to obj or data contained in it. Why does the lifetime of the borrow extend to the entire function, and how do I fix this?
Here is a sequence of steps on how I arrived here - running the code should provide the associated compiler errors.
no explicit lifetimes
IteratorType needs lifetime
Unconstrained lifetime parameter
To clarify: I'd like to be able to make calls like this:
fn main() {
let obj: MyStruct = MyStruct { data : vec![] };
touch_all(&mut obj);
}
rather than having to call
touch_all(&mut &obj);
which would be needed for the proposal by mcarton (1st and 2nd comment).

Why doesn't the lifetime of a mutable borrow end when the function call is complete?

I'm writing a bot for halite.io, and am having issues understanding some of the effects of borrowing. Here is the code that will not compile:
let scanLoc = hlt::types::Location {
x: oflow(coord.0 + l.x as i32, game_map.width),
y: oflow(coord.1 + l.y as i32, game_map.width),
};
let scan = game_map.get_site(scanLoc, types::STILL);
if (&scan.owner != id) | (scan.owner != 0u8) {
let ang = game_map.get_angle(l, scanLoc);
debug!("angle b/w: {}", ang);
return (l, 2);
}
This is the compiler error:
error[E0502]: cannot borrow `*game_map` as immutable because it is also borrowed as mutable
--> src/MyBot.rs:112:27
|
110 | let scan = game_map.get_site(scanLoc, types::STILL);
| -------- mutable borrow occurs here
111 | if (&scan.owner != id) | (scan.owner != 0u8) {
112 | let ang = game_map.get_angle(l, scanLoc);
| ^^^^^^^^ immutable borrow occurs here
...
116 | }
| - mutable borrow ends here
This is the code for the GameMap functions and struct:
#[derive(Clone, Debug)]
pub struct GameMap {
pub width: u16, // Number of columns.
pub height: u16, // Number of rows.
pub contents: Vec<Vec<Site>>,
}
impl GameMap {
pub fn in_bounds(&self, l: Location) -> bool {
// ...
}
pub fn get_distance(&self, l1: Location, l2: Location) -> u16 {
// ...
}
pub fn get_angle(&self, l1: Location, l2: Location) -> f64 {
// ...
}
pub fn get_location(&self, l: Location, d: u8) -> Location {
// ...
}
pub fn get_site(&mut self, l: Location, d: u8) -> &mut Site {
// ...
}
}
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Editor's note: This specific problem has been solved by the introduction of non-lexical lifetimes.
Let's look at a tiny reproduction:
struct Site {
owner: u8,
}
struct GameMap {
site: Site,
}
impl GameMap {
fn do_anything(&self) {}
fn get_site(&mut self) -> &mut Site {
&mut self.site
}
}
fn main() {
let mut game_map = GameMap {
site: Site { owner: 0 },
};
let site = game_map.get_site();
game_map.do_anything();
}
error[E0502]: cannot borrow `game_map` as immutable because it is also borrowed as mutable
--> src/main.rs:22:5
|
21 | let site = game_map.get_site();
| -------- mutable borrow occurs here
22 | game_map.do_anything(); // Compiler error!
| ^^^^^^^^ immutable borrow occurs here
23 | }
| - mutable borrow ends here
Our GameMap only owns a single Site, but that's enough. The call to get_site returns a reference (in this case it happens to be mutable):
fn get_site(&mut self) -> &mut Site
Thanks to lifetime elision, this is the same as
fn get_site<'a>(&'a mut self) -> &'a mut Site
This means that the returned reference is allowed to point to something inside of GameMap (which it does). Then we keep that reference in a variable - site!
That means that we can no longer use any immutable references to game_map as they might have been (or will in the future be) invalidated by the changes that can be made to the map through the mutable reference:
At any given time, you can have either one mutable reference or any number of immutable references.
References must always be valid.
— The Rust Programming Language chapter on references and borrowing
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Rust borrows your struct mutably because you are calling a method that requires a mutable reference (&mut self). That method then returns a mutable reference, transferring the borrow of the struct to the returned value. The borrow ends when the returned value goes out of scope.
So, how do you fix it? Probably the most flexible solution is to introduce a scope to constrain the mutable borrow:
let zhu_li_do_the_thing = {
let site = game_map.get_site();
site.owner == 5 || site.owner == 42
};
if zhu_li_do_the_thing {
game_map.do_anything();
}
Another is the same idea, but requires that you never store the borrow in a variable at all. Thus the mutable borrow doesn't last beyond that statement:
if game_map.get_site().owner == 42 {
game_map.do_anything();
}
It's common for idiomatic Rust code to have foo and foo_mut variants of a method, for when you don't need mutability. This may not help if you need to mutate game_map while the immutable borrow of site is still outstanding.
fn get_site(&self) -> &Site {
&self.site
}
fn get_site_mut(&mut self) -> &mut Site {
&mut self.site
}
let site = game_map.get_site();
if site.owner == 5 || site.owner == 42 {
game_map.do_anything();
}
See also:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
What are non-lexical lifetimes?

Resources