让我们从 abandon 开始--用 rust 写链表
虽然 Rust 的标准库中已经有了一个LinkedList数据结构,但创建自己的数据结构是了解更多 Rust 的一种有趣的方式。
节点
让我们首先定义我们的 Node 结构来保存模版。我们的 Node 将包含一个数据项,以及 Node 可能存在或可能不存在的上一个和下一个数据项。
/// A node containing a data item and links to previous and next nodes.
struct Node<T> {
data: Rc<T>,
prev: Link<T>,
next: Link<T>,
}
通过将数据项存储在引用计数器指针 ( Rc) 中,在创建新节点时无需克隆或复制数据。 Rust 需要在编译时知道结构的大小,这会导致自引用数据类型出现一些问题。prev如果我们将和字段的类型设置next为Node,我们会收到如下所示的编译器错误消息:
error[E0072]: recursive type `Node` has infinite size
--> src/data_structures/linkedlist.rs:127:1
|
127 | struct Node<T> {
| ^^^^^^^^^^^^^^
128 | data: Rc<T>,
129 | prev: Node<T>,
| ------- recursive without indirection
编译器错误消息为我们提供了如何继续操作的提示。我们正在被推动使用间接,这是谈论指针的另一种方式。 为了处理这个编译器错误,我们需要提供某种指针来代替Node. 我们可以定义一个自定义类型Link作为我们的间接Node包装器:
type Link<T> = Option<Rc<RefCell<Box<Node<T>>>>>;
请注意,因为我们的Link类型使用Rc(引用计数器指针)而不是Arc(原子引用计数指针),所以我们的实现Node不是线程安全的。
节点构造
我们的每个Node方法都将包含在一个块中:impl Node { ... } 这允许我们的方法获取通用类型的数据项T,使我们Node非常灵活!
现在我们知道我们的意志如何Node链接到其他人,我们可以实现该new()方法。每个都Node将开始作为通用类型的数据项保存T,并且不连接到上一个或下一个Node。
/// Creates a new Node containing the given data item. The previous and next
/// node links are set to None.
fn new(data: T) -> Node<T> {
Node {
data: Rc::new(data),
prev: None,
next: None,
}
}
Node setters
我们更新前一个和下一个节点