Rust中使用+=运算符时混用可变与不可变引用为何有时合法有时报错
错误原因和编译差异解释
这个问题的核心是Rust的表达式求值顺序、非词法生命周期(NLL) 和借用规则共同作用的结果:
1. B行编译报错的原因
复合赋值运算符(+=、-=等)的求值顺序是:先计算左侧的左值(存储位置),再计算右侧的右值,最后执行运算赋值。
B行*x.get_a_mut() += x.get_a();的执行流程:
- 第一步调用
x.get_a_mut(),会对*x产生一个可变借用,且这个借用指向结构体内部的a字段,需要持续到赋值写入完成才会释放 - 第二步计算右侧
x.get_a(),需要对*x产生不可变借用,此时可变借用还处于存活状态,违反了「同一时间不能同时存在指向同一对象的可变借用和不可变借用」的规则,因此编译器抛出E0502错误。
2. D行可以正常编译的原因
普通赋值运算符(=)的求值顺序和复合赋值完全相反:先计算整个右侧表达式的结果,再计算左侧的左值,最后执行赋值。
D行*x.get_a_mut() = x.get_a() + x.get_a();的执行流程:
- 第一步计算右侧的加法表达式:两次调用
x.get_a()产生的不可变借用都是临时的,拿到拷贝后的i64值完成加法运算后,这两个不可变借用就立刻释放了 - 第二步调用
x.get_a_mut()获取可变借用,此时没有其他存活的借用,没有冲突,赋值可以正常完成。
3. C行可以正常编译的原因
C行虽然同样使用了+=复合赋值,但NLL特性可以精准判断借用的实际存活范围,避免了冲突:
右值2 * x.get_a()中,x.get_a()返回的不可变引用只会在乘法运算阶段存活,解引用拷贝出i64数值后就立刻释放,不会持续到后续的赋值写入阶段。而get_a_mut()返回的可变借用只有在实际写入时才会被使用,两者的存活范围完全没有重叠,因此不会触发借用冲突。
内容的提问来源于stack exchange,提问作者andreasdr
相关产品推荐
相关产品推荐

