0

I have a mutable reference to an Environment struct which holds some data. My mutable functions on that struct (like create_data) returns a read only reference to the newly created memory. I would like to add multiple pieces of data to my Environment and return read only references to that data. However, when I try to do this with Rust immutable references I run into Rust’s “multiple mutable borrows” error.

Rust’s immutable references guarantee that the underlying data does not change. I’m not sure I need that guarantee. Is there a way I could get a “read-only” reference which does not guarantee the memory it points to is frozen?

Here’s a program that reproduces my issue with immutable references.

struct Environment {
    data: Vec<Data>,
}

#[derive(Debug)]
struct Data(u8);

#[derive(Debug)]
struct DataRef<'a>(&'a Data);

impl Environment {
    fn new() -> Environment {
        Environment { data: Vec::new() }
    }

    fn create_data(&mut self, i: u8) -> &Data {
        self.data.push(Data(i));
        &self.data[self.data.len() - 1]
    }
}

fn f<'a>(environment: &'a mut Environment) -> (DataRef<'a>, DataRef<'a>) {
    let a = DataRef(environment.create_data(1));
    let b = DataRef(environment.create_data(2));
    (a, b)
}

fn main() {
    println!("{:?}", f(&mut Environment::new()));
}

(Rust Playground)

Compiler error:

error[E0499]: cannot borrow `*environment` as mutable more than once at a time
  --> src/main.rs:24:21
   |
23 |     let a = DataRef(environment.create_data(1));
   |                     ----------- first mutable borrow occurs here
24 |     let b = DataRef(environment.create_data(2));
   |                     ^^^^^^^^^^^ second mutable borrow occurs here
25 |     (a, b)
26 | }
   | - first borrow ends here

I’m not entirely sure how to title this question or how to search for answers.

Calebmer
  • 2,972
  • 6
  • 29
  • 36
  • 1
    You can't have an immutable reference to something and then mutate it. This is [described in the book under the rules of references](https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#the-rules-of-references). This code **is not safe** because the second `push` can invalidate the reference in `a`. – Shepmaster Jun 05 '18 at 17:02
  • 1
    I believe your question is answered by the answers of [Cannot borrow as mutable because it is also borrowed as immutable](https://stackoverflow.com/q/47618823/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jun 05 '18 at 17:05
  • Thanks, you’re right, you helped me refine my question. What I want is a “read-only” reference I guess. I don’t need the frozen guarantee of immutable references. Is there a way to achieve this in Rust? My previous design for this code was to return the array index from `create_data`, but I’d like for Rust to guarantee the memory exists if possible. – Calebmer Jun 05 '18 at 17:20
  • 1
    *I’d like for Rust to guarantee the memory exists if possible* — That's my point; when you call `Vec::push`, the referenced memory may no longer be valid. Rust is already telling you that the code can lead to undefined behavior and cause crashes (if it compiled). Looking at it a different way, there's no way it can tell that `push` isn't the same as `clear`. – Shepmaster Jun 05 '18 at 17:26
  • I see. This answers my question. – Calebmer Jun 06 '18 at 01:06

0 Answers0