Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RefMut borrowed from Option does not live long enough (Option<Rc<RefCell<Node>>>)

First of all, I apologize if this question has been asked before. The only similar problem I could find was this (but it seems different) :

Cyclic reference does not live long enough

My code is :

use std::cell::RefCell;
use std::rc::Rc;

type NodePointer = Option<Rc<RefCell<Node>>>;

#[derive(Debug)]
struct Node {
    pub value : i32,
    pub next : NodePointer
}

fn main() {
    let mut vector = vec![None; 2];
    let new_node = Rc::new(RefCell::new(Node {
                value : 0,
                next : None
            }));
    vector[1] = Some(Rc::clone(&new_node));
    let new_node = Rc::new(RefCell::new(Node {
                value : 0,
                next : Some(Rc::clone(&new_node))
            }));
    vector[0] = Some(new_node);
    println!("{:?}", vector);

    // the following 3 lines would represent a body of the loop
    let mut a = vector[0].as_ref(); // Option<&Rc<RefCell<Node>>>
    let b = a.take().unwrap().borrow_mut(); // RefMut<Node>
    a = b.next.as_ref(); //ERROR : borrowed value 'b' does not live long enough

    println!("{:?}", vector);
}

The code below presents a short excerpt of my complete code. It is a bit weird, but variable 'a' would be used for looping over a vector (more than 2 values in complete code).

What I am trying to do is to make sure that variable 'a' is replaced with 'next' argument from vector[0] without modifying vector.

Compiler complains that 'b' does not live long enough, but I don't see why this is the case.

According to my understanding :

  • vector[0] is Option<Rc<...>>
  • variable 'a' is Option<&Rc<...>>
  • a.take() does not modify vector[0]
  • a.take() instead replaces 'a' with None
  • borrow_mut() should give a reference to vector[0], but for some reason it doesn't (?) <- I think this is the problem here
  • something happened to b, but I don't see what.

I am also aware that I could make use of Option::take() method instead of take_ref() (and it works in my complete code together with some additional modifications), but I would like to keep vector unmodified in-between 2 println statements

EDIT : for information, the following loop body would compile, but it modifies vector...

let mut a = vector[0].take(); // Option<&Rc<RefCell<Node>>>
let temp = a.unwrap();
let mut b = temp.borrow_mut(); // RefMut<Node>
a = b.next.take(); //ERROR : borrowed value 'b' does not live long enough
like image 336
rostyslav52 Avatar asked Oct 19 '25 03:10

rostyslav52


1 Answers

I may be wrong (still not 100% confident about the borrow checker), but I think the issue is this:

    // b borrows from a
    let b = a.take().unwrap().borrow_mut();
    // now, a borrows from b
    // note that the lifetime of `a` doesn't magically change just because you're not using the original value anymore
    // so from the type checker's perspective, a and b borrow from each other at the same time – not allowed
    a = b.next.as_ref();
    
    // btw, if you replace `a =` with `let c =` or even `let a =`, creating a new variable with a new lifetime, it compiles
    // let a = b.next.as_ref();
    // but doesn't work for us since you want to put it in a loop

And I think it makes sense. In the first iteration, you get a Option<&Rc<_>> by borrowing from vector. But if you had a Option<&Rc<_>> in the second iteration, where would it be borrowed from? You didn't take it from vector, you took it from stuff that only lived during the last iteration – it might be invalid. Or otherwise you would somehow need to ensure that all of the intermediate RefMuts somehow lived for the duration of the loop.

I don't think you can borrow something from one iteration to bring it to the next.

Instead, you should take advantage of the reference counting that you already have:

    let mut next = vector[0].clone();
    while let Some(node) = next {
        next = node.borrow_mut().next.clone();
    }

Now, next has type Option<Rc<_>> – shared ownership instead of a borrow.

like image 197
Reinis Mazeiks Avatar answered Oct 20 '25 19:10

Reinis Mazeiks



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!