让我们想象一下用Rust编写一个简单的链表。具体来说,让我们实现push_front()方法,它在链表的头部插入一个元素。
struct Node<T> {
val: T,
next: Option<Box<Node<T>>>,
}
struct LinkedList<T> {
head: Option<Box<Node<T>>>,
}
impl<T> LinkedList<T> {
fn push_front(&mut self, val: T) {
self.head = Some(Box::new(Node{val, next: self.head}))
}
}
error[E0507]: cannot move out of `self.head` which is behind a mutable reference
--> <source>:12:51
|
12 | self.head = Some(Box::new(Node{val, next: self.head}))
| ^^^^^^^^^ move occurs because `self.head` has type `Option<Box<Node<T>>>`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.
Compiler returned: 1
你也可以在编译器资源管理器中自己尝试一下。让我们深入了解一下编译器为什么会报错,根本原因有两个方面:
1,在可变引用&mut self之后,我们不能移动self.head值,就像编译器说的那样。这是因为如果我们移动self.head给其他变量,那么self.head进行drop之后就成为无效的,这样self也变成无效的了
2,Rust编译器还没有那么聪明。在代码中我们移动self.head到新的node中,然后我们立即给self.head赋一个新的有效值“self.head = Some(Box::new(Node{…}))”,不幸的是,编译器不能分析那么远。它只能分析一步,self.head被移出,这是不允许的。
pub fn replace<T>(dest: &mut T, src: T) -> T
impl<T> LinkedList<T> {
fn push_front(&mut self, val: T) {
// self.head = Some(Box::new(Node{val, next: self.head}));
let head = std::mem::replace(&mut self.head, None);
self.head = Some(Box::new(Node{val, next: head}))
}
}
impl<T> LinkedList<T> {
fn push_front(&mut self, val: T) {
// self.head = Some(Box::new(Node{val, next: self.head}));
self.head = Some(Box::new(Node{val, next: self.head.take()}));
}
}
fn pop_front(&mut self) -> Option<T>
如果头节点为空,则返回None
否则更新head以指向第二个节点并返回第一个值