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

如何创建可引用自身实例的Rust结构体?

问题分析与解决

错误原因

你遇到的E0382错误核心是所有权转移:

  • 执行let b = crate::Node::new(Some(a), 2);时,a的所有权被完全转移到b的prev字段中(被Box包裹)。
  • 由于Node未实现Copy trait,原变量a在所有权转移后不再属于当前作用域,后续访问a.id会触发编译器报错。

解决方案

根据不同需求,提供几种可行处理方式:

方案1:提前保存ID(仅验证ID相等场景)

如果只是要验证前后节点ID一致,无需保留原a实例,可提前存储a.id:

#[test]
fn test_children() {
    let a = crate::Node::new(None, 1);
    let a_id = a.id; // 提前保存ID值
    let b = crate::Node::new(Some(a), 2);

    assert_eq!(a_id, b.prev.unwrap().id);
}

方案2:使用Rc共享所有权(需保留原节点访问权)

如果需要同时持有a实例和b中对a的引用,可通过Rc(引用计数智能指针)实现共享所有权:
先修改结构体与new方法:

use std::rc::Rc;

pub struct Node {
    prev: Option<Rc<Node>>,
    id: u64,
}

impl Node {
    fn new(prev: Option<Rc<Node>>, id: u64) -> Node {
        Node { prev, id }
    }
}

再调整测试代码:

#[test]
fn test_children() {
    let a = Rc::new(crate::Node::new(None, 1));
    let b = crate::Node::new(Some(Rc::clone(&a)), 2);

    assert_eq!(a.id, b.prev.as_ref().unwrap().id);
}

Rc::clone仅增加引用计数,不会复制整个节点,这样a和b.prev都持有同一节点的所有权,避免了移动问题。

方案3:使用不可变引用(需处理生命周期)

如果不需要所有权共享,仅需临时引用,可调整结构体为持有引用并声明生命周期:

pub struct Node<'a> {
    prev: Option<&'a Node<'a>>,
    id: u64,
}

impl<'a> Node<'a> {
    fn new(prev: Option<&'a Node<'a>>, id: u64) -> Node<'a> {
        Node { prev, id }
    }
}

测试代码:

#[test]
fn test_children() {
    let a = crate::Node::new(None, 1);
    let b = crate::Node::new(Some(&a), 2);

    assert_eq!(a.id, b.prev.unwrap().id);
}

这种方式的限制是b的生命周期不能超过a,适合短期引用场景。

内容的提问来源于stack exchange,提问作者Karl Johannisson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:58:16