rust语言学习笔记(指针五)Weak<T>(弱引用,打破循环引用,防止内存泄漏)

  • Weak<T> 是一种‌非拥有性‌的引用。

  • 它‌不增加‌强引用计数,只增加一个独立的"弱引用计数"。

  • 当所有强引用消失时,数据会被立即释放,无论还有多少个 Weak 引用存在。

  • 访问 Weak 指向的数据时,必须先尝试将其"升级"(upgrade)为 RcArc。如果数据已被释放,升级会失败(返回 None)。

  • 主要方法:

    • Weak::new():创建一个空的弱引用。
    • Rc::downgrade(&rc):从强引用Rc<T>,创建弱引用Weak<T>
    • weak.upgrade(): 尝试将 Weak<T> 升级为 Option<Rc<T>>。如果数据已释放,返回 None

    • Rc::weak_count(&rc):获取指向该数据的弱引用数量(主要用于调试)。

5.1 双向链表 / 树结构(父子关系)

在树结构中,父节点持有子节点的强引用(拥有权),而子节点需要知道父节点是谁,但不能拥有父节点(否则形成环)。因此,子节点持有一个指向父节点的 Weak 引用。

rust 复制代码
use std::{
    cell::RefCell,
    rc::{Rc, Weak},
};

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,      // 指向父节点的弱引用
    children: RefCell<Vec<Rc<Node>>>, // 指向子节点的强引用
}

fn main() {
    // 创建一个父节点
    let node1 = Rc::new(Node {
        value: 1,
        parent: RefCell::new(Weak::new()),  // 指向父节点的弱引用,默认初始值为None
        children: RefCell::new(Vec::new()), // 指向子节点的强引用,默认初始值为空Vec
    });
    
    // 创建一个子节点
    let node2 = Rc::new(Node {
        value: 2,
        parent: RefCell::new(Weak::new()),  // 指向父节点的弱引用,默认初始值为None
        children: RefCell::new(Vec::new()), // 指向子节点的强引用,默认初始值为空Vec
    });
    
    *node2.parent.borrow_mut() = Rc::downgrade(&node1);  // 将node2的父节点弱引用指向node1
    node1.children.borrow_mut().push(Rc::clone(&node2)); // 将node2的强引用添加到node1的子节点Vec中
    
    println!("{:?}", node1);
    println!("{:?}", node2);
    println!("{:?}", node2.parent.borrow().upgrade());  // 将node2的父节点弱引用升级为强引用
}

5.2 图结构(无向图/网状结构)

rust 复制代码
use std::{
    cell::RefCell,
    rc::{Rc, Weak},
};

#[derive(Debug)]
struct Vertex {                              // 顶点
    value: i32,
    neighbors: RefCell<Vec<Weak<Vertex>>>,   // 邻居
}

fn main() {
    // 创建一个顶点v1,初始邻居为空Vec
    let v1 = Rc::new(Vertex {
        value: 1,
        neighbors: RefCell::new(Vec::new()), // 邻居,默认初始值为空Vec
    });

    // 创建一个顶点v2,初始邻居为空Vec
    let v2 = Rc::new(Vertex {
        value: 2,
        neighbors: RefCell::new(Vec::new()), // 邻居,默认初始值为空Vec
    });

    // 创建一个顶点v3,初始邻居为空Vec
    let v3 = Rc::new(Vertex {
        value: 3,
        neighbors: RefCell::new(Vec::new()), // 邻居,默认初始值为空Vec
    });

    v1.neighbors.borrow_mut().push(Rc::downgrade(&v2)); // 将v2添加到v1的邻居中
    v2.neighbors.borrow_mut().push(Rc::downgrade(&v1)); // 将v1添加到v2的邻居中
    v1.neighbors.borrow_mut().push(Rc::downgrade(&v3)); // 将v3添加到v1的邻居中

    println!("{:?}", v1);
    println!("{:?}", v2);

    println!(
        "{:?}",
        v1.neighbors
            .borrow()                // 获取v1的邻居的读取引用
            .iter()                  // 迭代v1的邻居
            .map(|w| w.upgrade())    // 将v1的邻居的弱引用升级为强引用
            .collect::<Vec<_>>()     // 收集升级后的强引用到Vec中
    );
}