简介:我是 Rust 新手,所以我决定通过实现双链表来练习。出于调试目的,我实现了该get()
方法,但未能从Rc<RefCell<_>>
. (抱歉问了个愚蠢的问题)
问题:我试图返回一个Result<T, &'static str>
in ,.get()
其中T
是节点中存储的数据的类型,&str
是错误消息字符串。借用检查器告诉我,我无法返回对方法内变量的引用,因此我尝试将内部值复制出来并返回它,但失败了。
源代码:
use std::{rc::Rc, cell::RefCell};
struct Node<T> {
data: Option<T>,
prev: Option<Rc<RefCell<Node<T>>>>,
next: Option<Rc<RefCell<Node<T>>>>,
}
impl<T> Node<T> {
/// Instantiate a new dummy node.
/// This node is used to mark the start and end of the list.
/// It is not counted in the size of the list.
fn new() -> Self {
Node {
data: None,
prev: None,
next: None,
}
}
/// Instantiate a new content node.
/// This node is used to store data.
/// It is counted in the size of the list.
fn from(data: T) -> Self {
Node {
data: Some(data),
prev: None,
next: None,
}
}
}
struct List<T> {
head: Rc<RefCell<Node<T>>>,
tail: Rc<RefCell<Node<T>>>,
size: usize,
}
impl<T> List<T> {
pub fn new() -> Self {
let head = Rc::new(RefCell::new(Node::new()));
let tail = Rc::new(RefCell::new(Node::new()));
head.borrow_mut().next = Some(Rc::clone(&tail));
tail.borrow_mut().prev = Some(Rc::clone(&head));
List { head, tail, size: 0 }
}
pub fn prepend(&self, data: T) {
let node = Rc::new(RefCell::new(Node::from(data)));
let mut head = self.head.borrow_mut();
node.borrow_mut().next = Some(head.next.take().unwrap());
node.borrow_mut().prev = Some(Rc::clone(&self.head));
head.next = Some(Rc::clone(&node));
if let Some(next) = node.borrow().next.as_ref() {
next.borrow_mut().prev = Some(Rc::clone(&node));
};
}
pub fn append(&self, data: T) {
let node = Rc::new(RefCell::new(Node::from(data)));
let mut tail = self.tail.borrow_mut();
node.borrow_mut().prev = Some(Rc::clone(&tail.prev.take().unwrap()));
node.borrow_mut().next = Some(Rc::clone(&self.tail));
tail.prev = Some(Rc::clone(&node));
if let Some(prev) = node.borrow().prev.as_ref() {
prev.borrow_mut().next = Some(Rc::clone(&node));
};
}
pub fn get(&self, index: isize) -> Result<T, &'static str> {
let mut current: Rc<RefCell<Node<T>>> = Rc::clone(self.head.borrow().next.as_ref().unwrap());
for _ in 0..index {
let tmp = Rc::clone(current.borrow().next.as_ref().ok_or("Index out of range")?);
current = tmp;
}
let result = current.borrow().data.as_ref().ok_or("Index out of range")?; // error[E0716]
Ok(*result) // error[E0507]
}
}
/*
error[E0716]: temporary value dropped while borrowed
--> src\linked.rs:74:22
|
74 | let result = current.borrow().data.as_ref().ok_or("Index out of range")?;
| ^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary value which is freed while still in use
75 | Ok(*result)
| ------- borrow later used here
|
help: consider using a `let` binding to create a longer lived value
|
74 ~ let binding = current.borrow();
75 ~ let result = binding.data.as_ref().ok_or("Index out of range")?;
|
error[E0507]: cannot move out of `*result` which is behind a shared reference
--> src\linked.rs:75:12
|
75 | Ok(*result)
| ^^^^^^^ move occurs because `*result` has type `T`, which does not implement the `Copy` trait
*/
我试过:
- 这篇关于对 value 进行引用的文章,但这就是我正在尝试做的事情,但失败了。
- 这篇文章关于修改 a
RefCell
,但这没有帮助。我试图归还它,而不是改变它。 - 这篇文章关于如何借用 a
RefCell
,但我无法归还借用的值,因为借用的值Rc
是短暂的(但内部值不是)。 - 这篇关于如何在 a 中返回某些内容的文章
RefCell
和这篇关于如何用 来返回它的文章.map()
,但是当我尝试使用.into()
和借用检查器时,编译器说“特征绑定不满足”,如果我删除 . 则编译器抱怨“无法移出”.into()
。 - 这篇关于使用 的文章
Rc::try_unwarp()
,但它不起作用,因为内部数据有多个所有者。
另外:我可能做错了,如果其中一篇文章解决了我的问题,但我没有以正确的方式实现它,请原谅我,并请教我如何正确地做到这一点。非常感谢。
你不知道。
如果值为
Copy
,则可以复制它。如果是Clone
,您可以克隆它。但如果不是,或者克隆成本太高呢?你运气不好。
内部可变性(如
RefCell
)对于 API 来说是不利的。它往往会跨越 API 边界传播,有时甚至完全阻止您实现它们。在实现内部(有时)是好的,但由于泄漏而不好。当然,有一种正确的方法来实现双向链表(因为std 有一个),但这种正确的方法需要不安全的代码。当您已经掌握 Rust 后,您可能想返回它作为练习。请务必阅读《使用太多的链表学习 Rust》。
这对我有用:
(游乐场链接)
您需要该行
where T: Clone
来启用该.clone()
方法。有人说为了学习 Rust 而实现双向链表是错误的……我很遗憾地报告他们是对的。当我开始时,我也做了同样的事情。我尝试的另一件事是编写光线追踪器;情况好多了。
核心数据结构是使用原始指针实现的。这意味着编写不安全的代码并在其周围放置安全的 API:这是一项高级 Rust 技能。