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

Rust中解引用借用与直接借用的差异及借用规则问询

Rust中解引用借用与直接借用的差异

环境: rustc 1.82.0 (f6e511eec 2024-10-15)


问题描述

你对借用场景下*&T与T的区别存在困惑:以下代码中let b = &mut *a可正常编译,但let b = &mut x编译失败;同时取消最后一行注释会触发cannot assign to *a because it is borrowed错误,希望理解背后的Rust借用规则。

fn annoying_borrow() {
    let mut x = Box::new(1);
    let a = &mut x;
    let b = &mut *a;
    // let b = &mut x; // error: cannot borrow `x` as mutable more than once at a time
    *a = Box::new(2);
    // *b = Box::new(3); // error: `*a` is assigned to here but it was already borrowed
}

核心差异与规则解析

1. 为什么&mut *a合法,&mut x不合法?

这本质是直接借用和**派生借用(Reborrow)**的区别:

  • 当创建let a = &mut x时,a作为x的可变引用,已经独占了对x的访问权——根据可变引用的独占规则,此时任何直接访问x的行为(比如&mut x)都会违反“同一时间只能有一个可变引用”的核心规则,因此编译报错。
  • 而&mut *a属于从已有可变引用派生新的可变引用(即Reborrow):编译器会识别出b是从a派生的,属于同一借用链,并非直接绕过a访问x。这种派生借用不会打破a的独占性,因为编译器会跟踪b的生命周期,确保它与a的后续使用不冲突。

2. 为什么*a = Box::new(2)合法,但取消*b = ...注释会报错?

这得益于Rust的**非 lexical 生命周期(NLL)**特性:

  • 在当前代码中,b创建后没有被实际使用(注释掉了*b的赋值),编译器会自动推断b的生命周期在*a = Box::new(2)之前就已结束,因此此时a的独占权已恢复,可以正常修改*a。
  • 若取消*b = Box::new(3)的注释,b的生命周期会延续到该行,此时a仍被b借用,根据可变引用的独占规则,不能同时存在活跃的可变引用和对原变量的修改操作,因此编译报错。

3. *&T与T的本质区别

*&T并非直接获取T的原始值,而是通过对引用的解引用,生成一个临时的借用视图。编译器会将其视为从原引用派生的新引用,而非直接访问原始变量。这种派生借用受限于原引用的生命周期,不会打破原引用的独占性或共享性;而直接使用T则是访问原始变量,会触发针对原始变量的借用检查。


借用规则的统一解释

Rust借用规则的核心从未改变,编译器的进化(如NLL)只是让规则的应用更灵活,而非修改核心逻辑:

  1. 独占性:同一时间,一个值要么只能有一个可变引用,要么可以有任意多个不可变引用,二者不可兼得。
  2. 有效性:引用必须始终指向有效的值,不能出现悬垂引用。
  3. 借用链兼容性:从已有引用派生的新引用(Reborrow)属于同一借用链,编译器会跟踪其生命周期,确保不会与原引用的使用冲突。

你在《Programming Rust(第二版)》中看到的描述,正是对上述核心规则的细化:

共享访问即只读访问
被共享引用借用的值是只读的。在共享引用的生命周期内,其指向的对象及该对象可访问的任何内容都无法被修改。该结构中不存在活跃的可变引用,其所有者也被视为只读,整个结构处于冻结状态。

可变访问即独占访问
被可变引用借用的值只能通过该引用访问。在可变引用的生命周期内,不存在其他可访问其指向对象或该对象可访问内容的路径。只有从该可变引用自身借用的引用,其生命周期才能与该可变引用重叠。

这些描述完全契合核心规则:共享引用的只读性对应“多个不可变引用共存”,可变引用的独占性对应“同一时间仅一个可变引用”,而派生引用的允许则是对“借用链兼容性”的说明。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 23:45:03