Rust Non-lexical lifetimes confusion

The Rust borrow-checker is REALLY annoying to deal with sometimes.
I have the following code:

      pub fn add_node(&mut self, data: T, v: usize) -> usize {
                self.adj.push(DigraphNode { data, edges: None });
                let e = &mut self.adj[v].edges;
                if e.is_none() {
                    e.replace(Vec::new());
                }
                {
                    let length = self.adj.len();
                }
               
                e.as_mut().unwrap().push(0);
            }

But borrowck incessantly complains that I can't borrow immutably because I also borrow mutably. Obviously this code should work. I don't even use length (I obviously want to use the value in the call to push). I even put a scope around it, but it still complains. What am I doing wrong here?

Since e is a mutable (exclusive) reference into self.adj, you can't get a shared reference to call self.adj.len(), even if it only exists for the duration of that call.

You could get the length before you acquire any exclusive reference:

let length = self.adj.len();

self.adj.push(DigraphNode { data, edges: None });
let e = &mut self.adj[v].edges;
if e.is_none() {
    e.replace(Vec::new());
}

e.as_mut().unwrap().push(length);
1 Like

So, is there no way to something like this?

self.adj[self.adj.len()-1).push(val)

What about using the last_mut() method to access the last element in a Vec/slice?

I'm not sure exactly what you're trying to do, as in your OP you were indexing on v, while with this latest question you're apparently trying to modify the thing you just added to self.adj.

For the former, I'd suggest a variation of @Cyborus's suggestion:

    pub fn add_node(&mut self, data: T, v: usize) -> usize {            
        let length = self.adj.len();
        self.adj.push(DigraphNode { data, edges: None });
        match self.adj[v].edges {
            Some(ref mut inner) => inner.push(length),
            None => self.adj[v].edges = Some(vec![length]),
        }

        length
    }

For the latter, I'd suggest just setting up the DiagraphNode before inserting it:

    pub fn add_node(&mut self, data: T) -> usize {   
        let length = self.adj.len();
        let edges = Some(vec![length]);         
        self.adj.push(DigraphNode { data, edges });
        length
    }

In both cases, I'm assuming that

  • You're trying to push the index of the newly inserted element into edges
  • You want to return the same value you push into edges

Thanks guys. I figured it out.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.