0

In the following MWE I have a struct A that contains a vector of AElem. Each AElem contains a map that references other AElems.

use std::collections::HashMap;

struct AElem<'b> {
    val: HashMap<String, &'b AElem<'b>>,
}

pub struct A<'b> {
    data: Vec<AElem<'b>>,
}

impl<'b> A<'b> {
    pub fn init() -> A<'b> {
        let mut data: Vec<AElem<'b>> = Vec::new();

        for _ in 0..10 {
            data.push(AElem { val: HashMap::new() });
        }

        for i in 0..data.len() {
            let (left, right) = data.split_at_mut(i);
            for j in i - 1..=0 {
                right[0].val.insert(format!("{}-{}", i, j), &left[j]);
            }
        }

        println!("{}", data.len());

        A { data }
    }
}

fn main() {
    A::init();
}

Playground

The main challenge lies within the storing of references to other AElems in the map. For that I need two references to data; A mutable for manipulating val, and an immutable which I use as a reference for the map. That I achieve using split_at_mut. However, I get three compilation errors, that do not really make sense to me (in the context of this code).

error[E0499]: cannot borrow `data` as mutable more than once at a time
  --> src/main.rs:20:33
   |
11 | impl<'b> A<'b> {
   |      -- lifetime `'b` defined here
12 |     pub fn init() -> A<'b> {
13 |         let mut data: Vec<AElem<'b>> = Vec::new();
   |                       -------------- type annotation requires that `data` is borrowed for `'b`
...
20 |             let (left, right) = data.split_at_mut(i);
   |                                 ^^^^^^^^^^^^^^^^^^^^ `data` was mutably borrowed here in the previous iteration of the loop

I absolutely get that there cannot be multiple mutable references at the same time. However, I do not understand why there are multiple in my code. Is is because I store &left[j] in the map? If so, what is the proper way to store &data[j]?

error[E0502]: cannot borrow `data` as immutable because it is also borrowed as mutable
  --> src/main.rs:26:24
   |
11 | impl<'b> A<'b> {
   |      -- lifetime `'b` defined here
12 |     pub fn init() -> A<'b> {
13 |         let mut data: Vec<AElem<'b>> = Vec::new();
   |                       -------------- type annotation requires that `data` is borrowed for `'b`
...
20 |             let (left, right) = data.split_at_mut(i);
   |                                 -------------------- mutable borrow occurs here
...
26 |         println!("{}", data.len());
   |                        ^^^^^^^^^^ immutable borrow occurs here

Why are there still mutable references to data at this point?

error[E0505]: cannot move out of `data` because it is borrowed
  --> src/main.rs:28:13
   |
11 | impl<'b> A<'b> {
   |      -- lifetime `'b` defined here
12 |     pub fn init() -> A<'b> {
13 |         let mut data: Vec<AElem<'b>> = Vec::new();
   |             --------  -------------- type annotation requires that `data` is borrowed for `'b`
   |             |
   |             binding `data` declared here
...
20 |             let (left, right) = data.split_at_mut(i);
   |                                 -------------------- borrow of `data` occurs here
...
28 |         A { data }
   |             ^^^^ move out of `data` occurs here

This error I do not get at all. Is there possibly something wrong with the lifetime specifiers?

jeanggi90
  • 741
  • 9
  • 24
  • First question: Do you really need references here? What about the branch being `AElem` or a boxed version if required? – tadman Apr 25 '23 at 00:54
  • You are trying to create a self-referential struct, which is impossible in safe rust (explained in the link above), and what you're doing here is also impossible in unsafe rust. If the `Vec` gets reallocated, all the references will point to the old buffer and are therefore invalid. – drewtato Apr 25 '23 at 01:37

0 Answers0