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

如何存储生命周期不超过其容器的Rust引用?

问题分析与解决方案

编译错误的核心原因很明确:set_i方法把self的可变引用生命周期强行绑定到了ShallowArray的泛型生命周期'a,导致调用该方法后,arr会被持续可变借用直到'a结束(也就是arr1的生命周期,到test函数末尾)。但函数末尾要执行ShallowArray的Drop逻辑,此时arr还处于被借用状态——Rust的借用检查器不允许这种冲突,因为Drop会获取&mut self,和已有的可变借用互斥。

修复步骤

1. 修正set_i方法的生命周期签名

把原来的fn set_i(&'a mut self, idx: usize, obj: &'a Array)改成fn set_i(&mut self, idx: usize, obj: &'a Array)。去掉self引用上的'a绑定,只保留参数obj的'a生命周期约束:既保证存储的引用生命周期不超过容器,又不会把self的借用锁死到'a。

2. 修复后完整代码

use std::alloc::{alloc, dealloc, Layout};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;

#[repr(C)]
struct Array {
    size: usize,
    arr: *mut Array,
}
// Drop for Array deallocates array recursively
impl Drop for Array {
    fn drop(&mut self) {
        if self.size > 0 && !self.arr.is_null() {
            let layout = Layout::array::<Array>(self.size).unwrap();
            unsafe {
                for i in 0..self.size {
                    std::ptr::drop_in_place(self.arr.add(i));
                }
                dealloc(self.arr as *mut u8, layout);
            }
        }
    }
}

// must have same representation as Array
#[repr(C)]
struct ShallowArray<'a> {
    inner: ManuallyDrop<Array>,
    _phantom: PhantomData<&'a Array>,
}
impl<'a> ShallowArray<'a> {
    fn new(size: usize) -> Self {
        let layout = Layout::array::<Array>(size).unwrap();
        let arr = unsafe { alloc(layout) } as *mut Array;
        unsafe {
            std::ptr::write_bytes(arr, 0, layout.size());
        }
        Self {
            inner: ManuallyDrop::new(Array { size, arr }),
            _phantom: PhantomData,
        }
    }
    // 去掉self引用上的'a绑定
    fn set_i(&mut self, idx: usize, obj: &'a Array) {
        if idx >= self.inner.size {
            panic!("Index out of bounds");
        }
        unsafe {
            *self.inner.arr.add(idx) = Array {
                size: obj.size,
                arr: obj.arr,
            };
        }
    }
}
impl Drop for ShallowArray<'_> {
    fn drop(&mut self) {
        // deallocate only the first level
        let layout = Layout::array::<Array>(self.inner.size).unwrap();
        unsafe {
            dealloc(self.inner.arr as *mut u8, layout);
        }
    }
}
fn test() {
    let arr1 = Array {
        size: 0,
        arr: std::ptr::null_mut(),
    };
    let mut arr = ShallowArray::new(3);
    arr.set_i(0, &arr1);
}

fn main() {
    test();
}

关键逻辑说明

  • ShallowArray<'a>的PhantomData<&'a Array>用来告诉编译器:结构体持有生命周期为'a的Array引用(内部裸指针通过PhantomData标注生命周期约束),确保存储的指针指向的Array至少和ShallowArray存活时间一致。
  • set_i方法只约束obj的生命周期为'a,不需要绑定self的引用,这样调用方法后self的可变借用会立即释放,不会干扰后续的Drop执行。
  • ManuallyDrop<Array>用来避免触发Array的递归Drop逻辑,因为ShallowArray只负责释放自己分配的第一层数组,元素的释放由原Array自行处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 10:58:18