さびは奇妙な行動を借りる

Aug 22 2020

以下のrustコードのように:whileループはコンパイルされて正常に実行for iterされますが、エラーのためにバージョンはコンパイルされません:

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
  --> src/main.rs:22:9
   |
20 |     for i in v.iter() {
   |              --------
   |              |
   |              immutable borrow occurs here
   |              immutable borrow later used here
21 |         println!("v[i]: {}", i);
22 |         v.push(20);
   |         ^^^^^^^^^^ mutable borrow occurs here

error: aborting due to previous error

しかし、理解されるように、whileループにも同じシナリオを持っている、lengetして、それが競合しない理由も、immutably借りpushmutablyボローとして?ここで私の理解が欠けていることを教えてください、啓発してくれてありがとう!

fn main() {
    let mut v = Vec::new();
    
    
    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    
    let mut i = 0;
    
    while i < v.len() && i < 10 {
        
        v.push(20);
        println!("v[i]: {:?}", v.get(i));
        i += 1;
    }
    
    // for i in v.iter() {
    //     println!("v[i]: {}", i);
    //     v.push(20);
        
    // }
    
}

回答

3 Herohtar Aug 21 2020 at 23:31

forコードのバージョンは、次のものとほぼ同等です。

fn main() {
    let mut v = Vec::new();
    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    
    let mut it = v.iter();
    while let Some(i) = it.next() {
        println!("v[i]: {}", i);
        v.push(20);
    }
}

遊び場

それをコンパイルしようとすると、おそらくもう少し意味のあるエラーが発生します。

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
  --> src/main.rs:11:9
   |
8  |     let mut it = v.iter();
   |                  - immutable borrow occurs here
9  |     while let Some(i) = it.next() {
   |                         -- immutable borrow later used here
10 |         println!("v[i]: {}", i);
11 |         v.push(20);
   |         ^^^^^^^^^^ mutable borrow occurs here

イテレータはvループの全期間にわたって不変に借用しているため、ループ内で変更可能な借用を行うことはできません。

もちろん、それができたとしても、別の項目を追加し続けるため、無限ループになってしまいます。

1 BlackBeans Aug 21 2020 at 23:21

お電話の際は簡単に言えば、.iter()あなたはあなたのベクトルを借りて、新しいオブジェクト(イテレータ)、(immutably)を作成し、あなたが実際に借り手段1によって要素の1を与えるループの全体の時間を。一方、を介してアクセスすると、ベクトルから一度に1つの要素を直接借用するため、借用の制限から解放されます。v.get(i)push

このような制限の理由は非常に単純です。実際のforループがコンパイルされ、永久に実行されると想像してください(whileループでこれを防ぐには、人工的な条件を追加する必要がありましたi<10!)が、これは明らかに意図された目標ではありません(またはそれはあなたが他の方法でそれを明らかにするだろう、例えばwhile letまたはloopステートメントで)、そしてあなたが本当にやりたいことをする方法がないので、Rustはあなたが「自分を足で撃つ」のを防ごうとします、そして間違って試みます仕方。

あなたがやりたいことをするために、あなたはすることができます:

for i in 0..v.len() {
    v.push(20)
}

なぜなら、v.len()呼び出しはループv全体の時間ではforなく、最初にのみ借用するからです。