如何为合并的单链表与二叉树结构实现Drop以避免StackOverflow
Rust混合链/树结构的Drop trait实现问题
以下是我当前的代码实现:
use std::rc::Rc; #[derive(Debug)] enum Value { Chain(Chain), Invalidate, } #[derive(Debug)] enum Chain { Link(Rc<Link>), Cons(Rc<Cons>), } #[derive(Debug)] struct Link { next: Value, } #[derive(Debug)] struct Cons { left: Value, right: Value, } impl Value { fn link(next: Value) -> Value { Value::Chain(Chain::Link(Rc::new(Link { next }))) } fn cons(left: Value, right: Value) -> Value { Value::Chain(Chain::Cons(Rc::new(Cons { left, right }))) } fn take(&mut self) -> Value { std::mem::replace(self, Value::Invalidate) } fn get_mut_link(&mut self) -> Option<&mut Link> { match self { Value::Chain(chain) => chain.get_mut_link(), _ => None, } } fn get_mut_cons(&mut self) -> Option<&mut Cons> { match self { Value::Chain(chain) => chain.get_mut_cons(), _ => None, } } } impl Chain { fn get_mut_link(&mut self) -> Option<&mut Link> { match self { Chain::Link(link) => Rc::get_mut(link), _ => None, } } fn get_mut_cons(&mut self) -> Option<&mut Cons> { match self { Chain::Cons(cons) => Rc::get_mut(cons), _ => None, } } } impl Drop for Value { fn drop(&mut self) { println!("NEW CALL"); let mut stack = vec![self.take()]; while let Some(mut value) = stack.pop() { { println!("STACK {}", stack.len()); // println!("BEFORE {:?}", value); if let Some(link) = value.get_mut_link() { stack.push(link.next.take()); } if let Some(cons) = value.get_mut_cons() { stack.push(cons.left.take()); stack.push(cons.right.take()); } // println!("AFTER {:?}", value); println!("STACK {}", stack.len()); } } println!("{:?}", self) } } fn main() { let mut aaax = Value::cons( Value::cons( Value::cons(Value::Invalidate, Value::Invalidate), Value::cons(Value::Invalidate, Value::Invalidate), ), Value::cons( Value::cons(Value::Invalidate, Value::Invalidate), Value::cons(Value::Invalidate, Value::Invalidate), ), ); for _ in 1..100000 { aaax = Value::link(aaax); aaax = Value::cons(aaax, Value::Invalidate); } }
我清楚单独处理Link/Invalidate或Cons/Invalidate结构时的Drop实现方式:
- 对于
Link/Invalidate,可以用迭代遍历,处理下一个节点前覆盖当前Link; - 对于
Cons/Invalidate,需要拼接部分树结构。
但将两种逻辑合并时遇到了问题,对两种不同Chain类型进行match时会触发「X moved」错误。
目前我用一个通用方案临时解决了问题:
struct Link { children: Vec<Value> }
但我的场景里只会有1个或2个子节点,不想用这种通用方式。
内容的提问来源于stack exchange,提问作者Gensoki
相关产品推荐
相关产品推荐

