Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 遍历中RefCell借用的循环引用_Rust_Smart Pointers_Lifetime_Borrowing_Interior Mutability - Fatal编程技术网

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

Rust 遍历中RefCell借用的循环引用,rust,smart-pointers,lifetime,borrowing,interior-mutability,Rust,Smart Pointers,Lifetime,Borrowing,Interior Mutability,我正在学习Rust并尝试编写一个双链接列表。然而,我已经陷入了一个典型的迭代遍历实现中。我得到的印象是,借用检查器/放置检查器过于严格,当借用器从RefCell跨越函数边界时,无法推断其正确的使用寿命。我需要重复设置一个变量绑定(curr,在本例中)以借用其当前内容: use std::cell::RefCell; use std::rc::Rc; pub struct LinkedList<T> { head: Option<Rc<RefCell<Lin

我正在学习Rust并尝试编写一个双链接列表。然而,我已经陷入了一个典型的迭代遍历实现中。我得到的印象是,借用检查器/放置检查器过于严格,当借用器从
RefCell
跨越函数边界时,无法推断其正确的使用寿命。我需要重复设置一个变量绑定(
curr
,在本例中)以借用其当前内容:

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

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.
        // ...
        unimplemented!()
    }
}
使用NLL

错误[E0716]:借用时丢弃的临时值
-->src/lib.rs:22:20
|
22 | curr=curr.borrow().next.as|ref().unwrap()
|                    ^^^^^^^^^^^^^
|                    |
|创建在仍在使用时释放的临时文件
|在此处创建具有借用权限的临时文件。。。
23 |         }
|         -
|         |
|临时值在此语句末尾被释放

| ... 这里可能会用到借阅,当临时文件被删除并运行类型为'std::cell::Ref的析构函数时,这里有一个较小的复制,我相信它显示了相同的问题:

use std::cell::RefCell;

fn main() {
    let foo = RefCell::new(Some(42));
    let x = foo.borrow().as_ref().unwrap();
}
正如我读到的:

  • foo.borrow()
    返回一种智能指针。在这种情况下,智能指针的作用类似于一个
    &选项
  • as_ref()
    创建一个
    选项,其中内部引用与智能指针具有相同的生存期
  • 选项
    被丢弃,只产生一个
    &i32
    ,仍然具有智能指针的生命周期
  • 值得注意的是,智能指针
    Ref
    仅在语句中有效,但代码尝试将引用返回到
    Ref
    中,该引用将在语句中有效

    一般来说,解决方案是这样做:

    let foo_borrow = foo.borrow();
    let x = foo_borrow.as_ref().unwrap();
    
    这会延长智能指针的使用时间,从而允许引用的生存期在
    foo\u borrow
    (表示借用本身)存在的时间内有效


    在循环的情况下,没有什么可以做的,因为在到达下一个节点之前,您基本上希望借用前一个节点。

    您可以克隆
    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;
    }
    

    注意:借用检查器不太严格,它可以防止此处出现锯齿。如果不是这样,您可能会有易变性+别名,从而导致崩溃或内存损坏。@MatthieuM。这里哪里会出现别名?你有机会阅读吗?@Shepmaster:如果你不借用
    self
    就可以获得
    curr
    ,那么是什么阻止你在同一个方法体中再次获得
    curr
    ?没有什么。通过获取
    RefCell::borrow
    以仅借出在其结果生命周期内有效的引用,可以动态防止这种情况。谢谢您的回答。你是说在循环中没有办法做到这一点吗?我不确定你的例子是否能解决我的问题。@Tsukki不会说不行,但我不知道。当你递归地做这件事时,我假设有一个未偿还借款的隐式层次结构,允许它继续进行。谢谢,这成功了!但是,当我需要从下面几行中的
    curr
    借用mut时,我必须执行
    let next=curr.borrow_mut().next.take();匹配下一个{…}
    而不是简单地
    匹配curr.borrow_mut().next.take(){…}
    。编译器并不试图推断出什么。