如何真正正确地将可变引用转换为 Rust 中的不可变引用?

Arc*_*Bug 2 reference ownership rust borrow-checker

我之前搜索过这个问题,比如thisthis,但是按照第一个链接的解决方案并尝试将它们应用到我的代码中,rustc 似乎误解了我想要做的事情。

我想创建一个链表并为节点中间分配一些引用并打印它们的值。首先,我使它们可变,以便创建从 head ref 到 tail ref 的列表,然后我想将它们转换为不可变的,从 tail ref 到 head ref,这不会违反所有权规则。最后,我想访问一些不可变的引用(中点)来获取它们的值。

我的代码:(游乐场

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
    );
}
Run Code Online (Sandbox Code Playgroud)

这里出了问题,rustc 仍然报告说我尝试将它们借用为不可变的,因为它们是由可变的 ref 借用的。但我之前已经将 ref 转换为不可变的。为什么?

有什么解决方案可以让我的程序按预期运行吗?

Cha*_*man 5

你不能。

您可以将可变引用转换为不可变引用,如链接的问题所示,但该对象仍将被可变地借用。

这对于Cell::from_mut()健全的 API 来说是必要的:它们将可变引用转换为不可变引用,并依赖对象继续可变借用。

如果需要,您可以next一成不变地重新跟踪指针:

let head = &*head;
let a = &head.as_ref().unwrap().next;
let b = &a.as_ref().unwrap().next;
let c = &b.as_ref().unwrap().next;
Run Code Online (Sandbox Code Playgroud)

游乐场

但实际上,整个链表式编程并不真正适合 Rust。