[英]Cannot add-assign within `Vec` of user-defined type
考虑以下代码( Rust Playground ):
#[derive(Clone, Copy, Debug)]
struct X(i32);
impl std::ops::AddAssign for X {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
fn main() {
let mut ary_i32 = [1_i32; 2];
ary_i32[0] += ary_i32[1]; // OK
let mut ary_x = [X(1); 2];
ary_x[0] += ary_x[1]; // OK
let mut vec_i32 = vec![1_i32; 2];
vec_i32[0] += vec_i32[1]; // OK
let mut vec_x = vec![X(1); 2];
vec_x[0] += vec_x[1]; // error[E0502]: cannot borrow `vec_x` as immutable because it is also borrowed as mutable
}
为什么我只在vec_x
线上得到 E0502? 我不明白为什么只允许ary_x
和vec_i32
的操作。 借用检查器是否特别对待内置类型( i32
, array
)?
我研究了一些资源并阅读了我的代码的 MIR,并设法了解发生了什么。
@trentcl 的评论将是最好的答案。 我尽可能详细地写。
对于array
,不使用Index
和IndexMut
特征,编译器直接操作数组元素(您可以使用 MIR 看到这一点)。 所以,这里不存在借款问题。
解释Vec
, rustc 指南很有用。
首先, 两阶段借用不适用于vec_foo[0] += vec_foo[1]
语句。
而且, i32
和X
之间的差异是由于操作符降低造成的。
Basically, statements like vec_user_defined[0] += vec_user_defined[1]
are converted to function calls like add_assign(index_mut(...), *index(...))
, and function arguments are evaluated from left to right. 因此, index_mut()
可变地借用x
并且index()
尝试借用x
,但失败了。
但是对于像i32
这样的内置类型,复合赋值运算符不会转换为 function 调用,并且 rhs 在 lhs 之前被评估(你可以看到index()
在index_mut()
和 MIR 之前被调用)。 因此,对于内置类型, vec_builtin[0] += vec_builtin[1]
有效。
我从lo48576 的文章(日文)中知道了这些事情。
我考虑了一些解决方法:
Vec
转换为slice
。 但这不适用于多维Vec
。Rust arrays 存在于堆栈中,大小可预测,因此具有更强的借用检查器保证。 向量是堆栈上的智能指针,指向可以在堆上增长和缩小的数据。 因为最后一个示例使用 Vector 类型,借用检查器在从堆加载时将整个 Vector 视为单个可变借用的 object。
正如您所观察到的,借用检查器可以创建对单个元素的可变引用,以指向存在于堆栈上的东西,而它创建对堆栈上 Vector 智能指针的可变引用,然后进一步可变引用上的数据堆。 这就是对vec_vec_x[1][1]
的不可变引用失败的原因。
正如@sebpuetz 在评论中指出的那样,您可以通过首先将不可变引用复制到vec_vec_x[1][1]
来解决此问题,然后创建不可变引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.