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

为何Rust中UnsafeCell两种可变引用写法编译结果不同?

为什么&mut unsafe { *cell.get() }返回时编译失败,而unsafe { &mut *cell.get() }可以?

这本质是Rust对临时值的处理规则、引用与原始数据绑定关系的差异,并非“对同一对象的借用”,具体拆解如下:

1. unsafe { &mut *cell.get() }的工作逻辑

  • cell.get()返回指向UnsafeCell内部值的裸指针*mut i32。
  • 在unsafe块中,&mut *是将裸指针直接转换为可变引用,这个引用直接绑定到UnsafeCell持有的原始数据,其生命周期可以和输入参数&UnsafeCell<i32>保持一致(只要cell存在,内部数据就存在)。
  • 编译器能推断出该引用的生命周期与函数参数cell相同,因此可以安全作为返回值返回。

2. &mut unsafe { *cell.get() }编译失败的核心原因

  • unsafe { *cell.get() }是对裸指针解引用,由于i32是Copy类型,这一步会生成原始值的临时拷贝,而非直接引用原始数据。
  • 后续的&mut是对这个临时拷贝取可变引用,但临时值的生命周期仅局限于当前表达式(函数返回时,临时值会被立即销毁),返回该引用会导致悬垂引用,因此编译器直接报错“无法返回对临时值的引用”。

3. 为什么main函数中&mut unsafe { *cell.get() }能编译?

在main函数中,Rust会自动延长临时值的生命周期,使其与持有该引用的变量(ref_compiles_fine_2)生命周期一致。但要注意:这个引用指向的是临时副本,而非UnsafeCell内部的原始数据。你可以通过修改值验证这一点:

fn main(){
    let cell = UnsafeCell::new(1);
    let ref_compiles_fine = unsafe { &mut *cell.get() };
    *ref_compiles_fine = 2;
    println!("原始cell值:{}", unsafe { *cell.get() }); // 输出2,修改的是原始数据

    let ref_compiles_fine_2 = &mut unsafe { *cell.get() };
    *ref_compiles_fine_2 = 3;
    println!("原始cell值:{}", unsafe { *cell.get() }); // 仍输出2,修改的是临时副本
}

总结

两种写法的本质完全不同:

  • unsafe { &mut *cell.get() }操作的是UnsafeCell内部的原始数据,引用生命周期绑定到cell本身;
  • &mut unsafe { *cell.get() }操作的是原始数据的临时拷贝,引用指向的是即将销毁的临时对象(函数返回场景)或独立的副本(main场景)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 16:56:26