繁体   English   中英

无法在用户定义类型的“Vec”中添加分配

[英]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_xvec_i32的操作。 借用检查器是否特别对待内置类型( i32array )?

我研究了一些资源并阅读了我的代码的 MIR,并设法了解发生了什么。
@trentcl 的评论将是最好的答案。 我尽可能详细地写。

对于array ,不使用IndexIndexMut特征,编译器直接操作数组元素(您可以使用 MIR 看到这一点)。 所以,这里不存在借款问题。

解释Vecrustc 指南很有用。
首先, 两阶段借用不适用于vec_foo[0] += vec_foo[1]语句。
而且, i32X之间的差异是由于操作符降低造成的。
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 的文章(日文)中知道了这些事情。

我考虑了一些解决方法:

  • 只需使用@sebpuetz 所说的中间变量即可。
  • 正如@trentcl 所说,将Vec转换为slice 但这不适用于多维Vec
  • 编写一些宏来自动引入一个中间变量。 我发现rhs_first_assign crate 做了这样的工作。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM