3

我正在学习 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

error[E0597]: borrowed value does not live long enough
  --> src/lib.rs:22:20
   |
22 |             curr = curr.borrow().next.as_ref().unwrap()
   |                    ^^^^^^^^^^^^^ temporary value does not live long enough
23 |         }
   |         - temporary value dropped here while still borrowed
...
28 |     }
   |     - temporary value needs to live until here
   |
   = note: consider using a `let` binding to increase its lifetime

使用 NLL

error[E0716]: temporary value dropped while borrowed
  --> src/lib.rs:22:20
   |
22 |             curr = curr.borrow().next.as_ref().unwrap()
   |                    ^^^^^^^^^^^^^
   |                    |
   |                    creates a temporary which is freed while still in use
   |                    a temporary with access to the borrow is created here ...
23 |         }
   |         -
   |         |
   |         temporary value is freed at the end of this statement
   |         ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, LinkedNode<T>>`
   |
   = note: consider using a `let` binding to create a longer lived value
   = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.

我真的很感激这个问题的迭代解决方案非递归)。

4

2 回答 2

2

您可以克隆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;
}
于 2016-04-14T05:47:41.997 回答
1

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

use std::cell::RefCell;

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

当我读到它时:

  1. foo.borrow()返回 a cell::Ref,一种智能指针。在这种情况下,智能指针的作用类似于&Option<i32>.
  2. as_ref()创建一个Option<&i32>内部引用与智能指针具有相同生命周期的地方。
  3. Option丢弃,只产生一个&i32, 仍然具有智能指针的生命周期。

值得注意的是,智能指针Ref仅在语句中持续存在,但代码会尝试返回对语句的引用,该引用Ref会比语句长。

通常,解决方案是执行以下操作:

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

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

在循环的情况下,您无能为力,因为您基本上想借用之前的每个节点,直到到达下一个节点。

于 2016-04-13T13:05:28.077 回答