请注意,此问题是指Rust 1.0之前的Rust版本.虽然语法已经改变,但这些概念仍然有效.
您可以使用拥有的指针轻松实现仅转发链接列表,例如:
struct Node<T> {
next: Option<~Node<T>>,
data: T
}
Run Code Online (Sandbox Code Playgroud)
但是,想象一下,如果您想要有效地实现支持四种基本操作的队列:
push:添加到列表的末尾pop:从列表末尾删除并返回unshift:添加到列表的前面shift:从列表末尾删除并返回在具有普通指针的语言中,您可以使用双向链表实现此操作,并使用根对象存储first和last指向列表中的第一个和最后一个元素.
我看不出你如何在Rust中实现它.
我可以模糊地猜测你会使用一堆引用,或许类似于:
struct Node<T> {
next: Option<&Node<T>>,
prev: Option<&Node<T>>,
data: T
}
Run Code Online (Sandbox Code Playgroud)
...但我看不出你如何管理这些变量的生命周期范围.
任何人都可以指出我的方向,或类似的例子涉及对象之间的引用复杂的生命周期?
(这种代码风格的另一个典型例子是观察者模式,其中许多对象必须将事件更新发布到单个位置,例如.UINode<> ---- EventObserver<> ---- EventCore<> ---- UINodes;多个对象一个复杂的层次结构共享指针,其中事件从叶节点传播到某个核心,然后被推送到不同的叶节点)
我以为我会通过改进一些非常简单的结构和算法来深入研究Rust,我开始使用链表.原来并不是那么简单.到目前为止这是我的代码:
enum List<T>
{
Node(T, ~List<T>),
Nil
}
impl<T> List<T>
{
fn new(vector: &[T]) -> List<T> { Nil }
fn add(&mut self, item: T)
{
let tail = self;
loop
{
match *tail
{
Node(_, ~ref next) => tail = next,
Nil => break
}
}
*tail = Node(item, ~Nil);
}
}
Run Code Online (Sandbox Code Playgroud)
这将无法编译,因为由于不兼容的可变性,下一个不能在match语句中分配给tail.我知道这可以很容易地使用垃圾收集指针来完成,但这种做法违背了练习的教育目的:我想知道如何在没有Gc或Rc指针的情况下做到这一点.
我想创建一个简单的链表并在其中添加一个值.如何add实现该方法以100 50 10 5在第42行进行此代码输出,第二次root.print()调用?
use std::rc::Rc;
struct Node {
value: i32,
next: Option<Box<Node>>,
}
impl Node {
fn print(&self) {
let mut current = self;
loop {
println!("{}", current.value);
match current.next {
Some(ref next) => {
current = &**next;
}
None => break,
}
}
}
fn add(&mut self, node: Node) {
let item = Some(Box::new(node));
let mut current = self;
loop {
match current.next {
None => current.next = item,
_ => {} …Run Code Online (Sandbox Code Playgroud)