Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to REALLY PROPERLY convert mutable reference to immutable reference in Rust?

I've searched about this question before, like this and this, but following the solution of the first link and try to apply them to my code, rustc seems misunderstand what I'm trying to do.

I wanted to create a linked list and assign some reference to the middle of the nodes and print their values. First I made them mutable in order to create the list from head ref to tail ref, then I wanted to convert them to be immutable, from tail ref to head ref, which wouldn't violate ownership rules. In the end, I wanted to access some immutable references(midway points) to get their values.

My code: (playground)

struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>,
}
impl<T> Node<T> {
    fn new(val: T) -> Option<Box<Node<T>>> {
        Some(Box::new(Node { val, next: None }))
    }
}
fn main() {
    let head = &mut Node::new(0);
    let a = &mut head.as_mut().unwrap().next;
    *a = Node::new(10);
    let b = &mut a.as_mut().unwrap().next;
    *b = Node::new(20);
    let c = &mut b.as_mut().unwrap().next;
    *c = Node::new(30);
    let tail = &mut c.as_mut().unwrap().next;
    *tail = Node::new(40);
    // Trying to make these mutable reference immutable.
    let tail = &*tail;
    // reference 'c' is converted to immutable,
    // so nothing borrows 'b' as mutable anymore
    let c = &*c;
    // Reports error anyway.
    // error[E0502]: cannot borrow `*b` as immutable
    // because it is also borrowed as mutable
    //  16 |     let c = &mut b.as_mut().unwrap().next;
    //     |                  ---------- mutable borrow occurs here
    // Didn't I just convert c to immutable?
    let b = &*b;
    let a = &*a;
    let head = &*head;
    println!(
        "a is {}, b is {}, c is {}",
        a.as_ref().unwrap().val,
        b.as_ref().unwrap().val,
        c.as_ref().unwrap().val
    );
}

Things had gone wrong here, rustc still reports that I try to borrow them as immutable because they are borrowed by ref that is mutable. But I already converted the ref to immutable before. Why?

Could there be any solution to make my program run as expected?

like image 717
ArchBug Avatar asked Apr 11 '26 18:04

ArchBug


1 Answers

You cannot.

You can convert a mutable reference to immutable one, as the linked questions show, but the object will still be borrowed mutably.

This is necessary for APIs like Cell::from_mut() to be sound: they convert a mutable reference to immutable, and rely on the object to continue be mutably borrowed.

If you want, you can re-follow the next pointers immutably:

let head = &*head;
let a = &head.as_ref().unwrap().next;
let b = &a.as_ref().unwrap().next;
let c = &b.as_ref().unwrap().next;

Playground.

But really, this whole linked-list-style-programming doesn't really fit into Rust.

like image 65
Chayim Friedman Avatar answered Apr 13 '26 10:04

Chayim Friedman