簡體   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