You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为合并的单链表与二叉树结构实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:10:20