Extracting mut ref from non-mut ref

I have a usual list (sigh...) and I want to save a mutable ref to one node for later.
I have this walking cycle:

        while let Some(ref node) = cur {
            if looks_interesting(){
                target = cur;
            }
            cur = &node.next;
          
        }

After cycle is done, I want to change content of the target. As far as I understand Rust safety this is safe: cur is gone and if only I have had a mutable reference in target, that's would be easy.

But target is shared, and I can't make it mut, as cur need to become mut, and I can't do it.

So, whilst I see that having mut target is totally safe, how can I pursue compiler to allow me do so?

1 Like

You can't do that. Rust enforces that mutable references are always exclusive, and you can never go from &T to &mut T.

1 Like

You can share mutable references (in a limited manner) via re-borrowing. So if your loop operates via &mut references, and target, if set, gets reborrowed to create the next cur, the whole thing becomes just about possible. In theory. If it wasn’t for limitations in the current borrow checker :sweat_smile:

I.e. with -Z polonius (unstable flag for a new experimental improved borrow checker) the following works

struct Node {
    contents: i32,
    next: List,
}

type List = Option<Box<Node>>;

fn looks_interesting(_: i32) -> bool {
    todo!();
}

fn foo(mut list: List) {
    let mut cur = &mut list;
    let mut target = &mut None;
    while let Some(mut node) = cur.as_mut() {
        if looks_interesting(node.contents) {
            target = cur;
            node = target.as_mut().unwrap(); // re-create `node`, borrowing from `target`
        }
        cur = &mut node.next;
    }

    // iteration done, now use target
    if let Some(target_node) = target.as_mut() {
        target_node.contents += 1;
    }
}
3 Likes

On stable rustc, the most straightforward approach might simply be to count the items, save the desired index in the list as a number, and in the end re-walk the list down to that index. Asymptotically, that’s likely not even less efficient.

The other, uglier option is to start heading down the RefCell/Mutex path to get interior mutability.

1 Like