【发布时间】:2015-06-15 04:20:20
【问题描述】:
作为 Rust 的一个学习项目,我有一个非常简单的(工作,如果不完整的话)单链表实现。结构的声明如下所示:
type NodePtr<T> = Option<Box<Node<T>>>;
struct Node<T> {
data: T,
next: NodePtr<T>,
}
pub struct LinkedList<T> {
head: NodePtr<T>,
}
实现 size 和 push_front 都相当简单,尽管迭代地执行大小确实涉及一些“与借用检查器的斗争”。
接下来我想尝试的是添加一个指向LinkedList 结构的tail 指针。启用高效的push_back 操作。在这里,我遇到了一点墙。起初我尝试使用Option<&Box<Node<T>>>,然后是Option<&Node<T>>。这两种情况都导致'as 到处都是,但最终仍然无法向生命周期检查器保证tail 是有效的。
从那以后,我得出的初步结论是,这些定义是不可能的:没有办法向编译器保证tail 在我认为的地方有效已验证。我可以做到这一点的唯一方法是让我的所有指针都是Rc<_> 或Rc<RefCell<_>>,因为这是让两个东西指向同一个对象(最终节点)的唯一安全方法。
我的问题:这是正确的结论吗?更一般地说:对于数据结构中的无主指针,惯用的 Rust 解决方案是什么?在我看来,对于如此简单的事情,引用计数似乎非常重要,所以我想我一定遗漏了一些东西。 (或者也许我只是还没有进入正确的记忆安全心态。)
【问题讨论】:
-
你是对的;如果没有像
Rc这样的东西所提供的共享所有权,就不可能在安全的 Rust 中表达循环。 -
这看起来是我问题的正确答案,但我也不想共享所有权。我想除了
Rc之外,我还会玩std::rc::Weak,因为我刚刚注意到前者存在。感谢您的快速回复! -
在我看来,对于如此简单的事情,引用计数似乎非常重要 =>当您开始关注所有权问题(谁拥有每条数据)时,你会意识到你对简单的印象是错误的:)
-
错误是一个强词;也许不同?这是一个棘手的陈述,因为在单链表中维护尾指针上的不变量非常非常容易——这是一个常见的高中 CS 主题。从数学上证明它们被维护是一个不同的问题。
标签: linked-list rust reference-counting