首页 文章

RefCell的循环引用在遍历中借用

提问于
浏览
2

我已经在典型的迭代遍历实现中陷入困境 . 我得到的印象是借用检查器/掉落检查器太严格,并且当它从 RefCell 越过函数边界时无法推断借用的正确生命周期 . 我需要重复设置一个变量绑定(在这种情况下为 curr )借用其当前内容:

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

pub struct LinkedList<T> {
    head: Option<Rc<RefCell<LinkedNode<T>>>>,
    // ...
}

struct LinkedNode<T> {
    value: T,
    next: Option<Rc<RefCell<LinkedNode<T>>>>,
    // ...
}

impl<T> LinkedList<T> {
    pub fn insert(&mut self, value: T, idx: usize) -> &mut LinkedList<T> {
        // ... some logic ...
            // This is the traversal that fails to compile.
            let mut curr = self.head.as_ref().unwrap();
            for _ in 1..idx {
                curr = curr.borrow().next.as_ref().unwrap()
            }
            // I want to use curr here.
        // ...
        }
    }
}

编译器抱怨借用的时间不够长 .

error: borrowed value does not live long enough
curr = curr.borrow().next.as_ref().unwrap()
       ^~~~~~~~~~~~~
note: reference must be valid for the destruction scope surrounding expression...
} else {
    let mut curr = self.head.as_ref().unwrap();
    for _ in 1..idx {
        curr = curr.borrow().next.as_ref().unwrap()
    }
note: ...but borrowed value is only valid for the expression at 60:28
    for _ in 1..idx {
        curr = curr.borrow().next.as_ref().unwrap()
    }

我真的很感激这个问题的 iterative solution (非递归) .

2 回答

  • 1

    您可以克隆 Rc 以避免终身问题:

    let mut curr = self.head.as_ref().unwrap().clone();
    for _ in 1..idx {
        let t = curr.borrow().next.as_ref().unwrap().clone();
        curr = t;
    }
    
  • 1

    这是一个较小的复制品,我认为它显示了同样的问题:

    use std::cell::RefCell;
    
    fn main() {
        let foo = RefCell::new(Some(42));
        let x = foo.borrow().as_ref().unwrap();
    }
    

    当我读到它:

    • foo.borrow() 返回cell::Ref,一种智能指针 . 在这种情况下,智能指针的作用类似于 &Option<i32> .

    • as_ref() 创建一个 Option<&i32> ,其中内部引用与智能指针具有相同的生命周期 .

    • Option 被丢弃,只产生 &i32 ,仍然具有智能指针的生命周期 .

    值得注意的是,智能指针 Ref 仅持续该语句,但代码尝试将引用返回到 Ref ,这将比语句更长 .

    通常,解决方案是做这样的事情:

    let foo_borrow = foo.borrow();
    let x = foo_borrow.as_ref().unwrap();
    

    这使智能指针保持更长时间,只要 foo_borrow (代表借用本身)存在,允许引用的生命周期有效 .

    在循环的情况下,你可以做的事情并不多,因为你基本上想要借用每个前一个节点,直到你到达下一个节点 .

相关问题