我正在跟随Learning Rust With Entirely Too Many Linked Lists在Rust写下我的第一个程序。我将程序更改为:
use std::mem;
#[derive(Debug)]
pub enum List {
Nil,
More(Box<Node>),
}
#[derive(Debug)]
pub struct Node {
val: i32,
next: List
}
impl List {
pub fn new() -> Self {
List::Nil
}
pub fn insert(&mut self, v : i32) {
let old_head = mem::replace(&mut *self, List::Nil);
let new_head = List::More(Box::new(Node { val : v, next: old_head}));
*self = new_head
}
pub fn remove(&mut self) -> Option<i32> {
match mem::replace(&mut *self, List::Nil) {
List::Nil => {
None
},
List::More(ref mut boxed_node) => {
let result = Some(boxed_node.val);
*self = mem::replace(&mut boxed_node.next, List::Nil);
result
}
}
}
}
impl Drop for List {
fn drop(&mut self) {
let mut head = mem::replace(&mut *self, List::Nil);
while let List::More(ref mut node) = mem::replace(&mut head, List::Nil) {
head = mem::replace(&mut node.next, List::Nil);
}
}
}
#[cfg(test)]
mod test {
use super::List;
#[test]
fn basics() {
let mut list = List::new();
list.insert(7);
assert_eq!(Some(7), list.remove());
assert_eq!(None, list.remove());
list.insert(1);
list.insert(2);
list.insert(3);
assert_eq!(Some(3), list.remove());
assert_eq!(Some(2), list.remove());
assert_eq!(Some(1), list.remove());
assert_eq!(None, list.remove());
}
#[test]
fn drop_long_list() {
let mut list = List::new();
for i in 1..100000 {
list.insert(i);
}
}
}
我的两个测试都在drop
中出现堆栈溢出失败。是因为RHS中的*self
吗?
我不知道let mut head = mem::replace(&mut *self, List::Nil);
发生了什么。
我的理解是:
List::Nil
中设置了self
。self
。head
的原始值
醇>
*self
还在做些什么吗?
我也试过这个版本的drop
:
impl Drop for List {
fn drop(&mut self) {
let mut head = mem::replace(self, List::Nil);
while let List::More(ref mut node) = mem::replace(&mut head, List::Nil) {
head = mem::replace(&mut node.next, List::Nil);
}
}
}
另一次尝试:
impl Drop for List {
fn drop(&mut self) {
while true {
match self {
&mut List::Nil => break,
&mut List::More(ref mut node) => {
*self = mem::replace(&mut node.next, List::Nil)
}
}
}
}
}
error[E0506]: cannot assign to `*self` because it is borrowed
--> src\list.rs:48:21
|
47 | &mut List::More(ref mut node) => {
| ------------ borrow of `*self` occurs here
48 | *self = mem::replace(&mut node.next, List::Nil)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `*self` occurs here
答案 0 :(得分:2)
您正在获得堆栈溢出,因为您的drop函数是无限递归的。
以下代码:
Class<T>
在let mut head = mem::replace(self, List::Nil);
中存储List
对象,该对象将在范围的末尾删除。这意味着,在您放弃时,您将创建一个也需要删除的新列表。重复这么多次就会出现堆栈溢出。
注意:在您关联的教程中,他们使用head
来避免递归。
答案 1 :(得分:2)
每当你编写递归(或迭代)代码时,你需要有一个停止条件。你的代码没有,所以它永远循环。
产生MCVE问题总是一个好的开始:
use std::mem;
#[derive(Debug)]
pub enum List {
Nil,
More(Box<List>),
}
impl Drop for List {
fn drop(&mut self) {
let mut head = mem::replace(self, List::Nil);
while let List::More(ref mut node) = mem::replace(&mut head, List::Nil) {
head = mem::replace(node, List::Nil);
}
}
}
#[test]
fn basics() {
List::Nil;
}
然后注释代码以查看它重复出现的位置:
fn drop(&mut self) {
eprintln!("1");
let mut head = mem::replace(self, List::Nil);
eprintln!("2");
while let List::More(ref mut node) = mem::replace(&mut head, List::Nil) {
eprintln!("3");
head = mem::replace(node, List::Nil);
eprintln!("4");
}
eprintln!("5");
}
打印出来
1
2
1
2
所以在那之后删除所有内容:
fn drop(&mut self) {
eprintln!("1");
let mut head = mem::replace(self, List::Nil);
eprintln!("2");
}
为什么会导致无限递归?您已对其进行了定义,以便放弃List
,您必须创建一个新的List
,然后需要将其删除,这会创建一个新的List
,其中...
添加停止条件:
fn drop(&mut self) {
if let List::Nil = *self { return }
let mut head = mem::replace(self, List::Nil);
while let List::More(ref mut node) = mem::replace(&mut head, List::Nil) {
head = mem::replace(node, List::Nil);
}
}
不再有无限的递归。
然后展开回原版并再试一次。它适用于此测试用例,但不适用于List::More(Box::new(List::Nil))
,因此我们将其缩小:
fn drop(&mut self) {
eprintln!("1");
if let List::Nil = *self { return }
eprintln!("2");
let mut head = mem::replace(&mut *self, List::Nil);
eprintln!("3");
while let List::More(ref mut node) = mem::replace(&mut head, List::Nil) {
eprintln!("4");
head = mem::replace(node, List::Nil);
eprintln!("5");
}
eprintln!("6");
}
1
2
3
4
1
5
1
2
3
4
1
5
现在的问题是,当我们重新分配head
时,需要删除我们覆盖的值,这会再次触发递归。
修复此问题复杂。就像,令人惊讶的那样。你准备好了吗?
impl Drop for List {
fn drop(&mut self) {
match *self {
List::Nil => return,
List::More(ref more) => {
if let List::Nil = **more {
return;
}
}
}
let mut head = mem::replace(self, List::Nil);
while let List::More(ref mut next) = {head} {
head = mem::replace(next, List::Nil);
}
}
}
现在有两个停止条件:
Nil
More(Nil)
在所有其他情况下,我们迭代地将More(x)
转换为More(Nil)
,这由停止条件处理。这意味着我们只有一个递归深度:为每个值在替换时head
的前一个值超出范围时被删除。
原始代码:
impl Drop for List {
fn drop(&mut self) {
match *self {
List::Nil => return,
List::More(ref more) => {
if let List::Nil = more.next {
return;
}
}
}
let mut head = mem::replace(self, List::Nil);
while let List::More(ref mut node) = {head} {
head = mem::replace(&mut node.next, List::Nil);
}
}
}
在您链接的原始教程中,这不是问题,因为List::drop
的定义根本不会修改self
,所以它不是自我递归的:
impl Drop for List {
fn drop(&mut self) {
let mut cur_link = mem::replace(&mut self.head, Link::Empty);
while let Link::More(mut boxed_node) = cur_link {
cur_link = mem::replace(&mut boxed_node.next, Link::Empty);
}
}
}