2017-03-01 4 views
2

一連のボックス化された値に対してイテレータを使用しています。私はこのイテレータを、ボックス化された値への変更可能な参照の上にマップしたいと思います。ルックの反復参照可能な値にボックス化された値をマップする

以下の簡略化された例は、不変参照に対してこれをどのように達成できるかを示しています。この例はうまくコンパイルされます。

let indices = [0usize, 1usize, 2usize]; 
let vec = vec![Box::new(1.0), Box::new(2.0), Box::new(3.0)]; 
let i = indices.iter().map(|index| vec[*index].deref()).map(|x| *x + 1.0); 

ただし、以下の例のように変更可能な参照の場合、コンパイラはエラーを生成します。

let indices = [0usize, 1usize, 2usize]; 
let mut vec = vec![Box::new(1.0), Box::new(2.0), Box::new(3.0)]; 
let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0); 

コンパイルエラーは以下の通りです:

これを固定することができる方法
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements 
    --> src\port_graph/mod.rs:200:40 
    | 
200 |  let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0); 
    |          ^^^^^^^^^^^ 
    | 
note: first, the lifetime cannot outlive the lifetime as defined on the body at 200:39... 
    --> src\port_graph/mod.rs:200:40 
    | 
200 |  let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0); 
    |          ^^^^^^^^^^^^^^^^^^^^^^^ 
note: ...so that closure can access `vec` 
    --> src\port_graph/mod.rs:200:40 
    | 
200 |  let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0); 
    |          ^^^ 
note: but, the lifetime must be valid for the scope of call-site for function at 200:39... 
    --> src\port_graph/mod.rs:200:40 
    | 
200 |  let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0); 
    |          ^^^^^^^^^^^^^^^^^^^^^^^ 
note: ...so that return value is valid for the call 
    --> src\port_graph/mod.rs:200:32 
    | 
200 |  let i = indices.iter().map(|index| vec[*index].deref_mut()).map(|x| *x = *x + 1.0); 
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

編集:単純なベクトルの場合、単純に以下を実行できます。しかし、上記の例は、グラフの中のノードの部分集合(petgraph crate)を繰り返したい場合の単純化です。グラフ自体を消費したくありません。

let mut vec = vec![Box::new(1.0), Box::new(2.0), Box::new(3.0)]; 
let i = vec.iter_mut().map(|boxed| boxed.deref_mut()).map(|x| *x = *x + 1.0); 

答えて

3

不変の参照と変更可能な参照の間には大きな違いがあります。借入のコア原則は次のとおりです。

エイリアシングXOR可変性

錆言語を使用すると、変更可能な参照を持っている場合は、同じオブジェクトのエイリアスは他の参照が存在しないことを保証します。代わりに、マッピングのあなたの場合は


、再び、のは...アドレスを収集してみましょう:

let c: Vec<_> = indices.iter().map(|index| vec[*index].deref()) 
           .map(|x| x as *const _ as usize) 
           .collect(); 
println!("{:?}", c); 

私たちは、ベクトルの要素のアドレスのリストを取得します。

これらのアドレスが異なる理由は、インデックスが異なるためです。私たちが卑劣で、indicesから[0, 1, 2, 1]まで初期化すると、エイリアシングが発生します。

ランタイムプロパティに基づいてエイリアスを取得できる場合は、変更可能ではありません。型システムはこれを強制する。


どのように強制されますか?

vecはクロージャによって借用されています。deref

  • 、閉鎖はderef_mut&Vec
  • を借りて、クロージャは&mut Vec

を借りあなたは最初のものを自分で目撃することができます

let i = indices.iter().map(|index| vec[*index].deref()) 
         .map(|x| x as *const _ as usize); 

vec[0] = Box::new(3.0); 

は、そのノートで失敗しますベクタはすでにクロージャによって不変に借用されています。したがって、閉鎖に変更可能なアクセスを必要と

  • deref_mutが取る引数で&mut self
  • も引数で&mut self取りIndexMutを必要とする、
  • もう一つは論理的拡張でありますベクター。

したがって、閉鎖を呼び出すたびに、&mut Vecにアクセスします。したがって、あなたが閉鎖何も呼び出さないたびに、この&mut Vecを別名必要があり、これにより、参照は閉鎖外に漏れてはなりません。

これはどのように達成されましたか?

あなたはクロージャ内へのアクセスを取得し、参照の寿命を締めて:あなたはクロージャを起動するたびに、あなたは'scopeは、クロージャ本体とこれ以上の範囲である&'scope mut Vecの参照を取得します。

(これもreborrowingと&mut TCopyではないという事実に関連:それはCopyないとして、あなたが内部に格納されている&mut Tのコピーを手渡しすることができないので、あなたが持っている再ボロー&mut *vecを手渡しされています新鮮な生涯)。


解決策は何ですか?

あなたはVecへのアクセス権を持って閉鎖に直接任意およびすべての計算を実行します。この閉鎖で、あなたはすべての後に変更可能なアクセス権を持っています。

fn main() { 
    let indices = [0usize, 1usize, 2usize]; 
    let mut vec = vec![Box::new(1.0), Box::new(2.0), Box::new(3.0)]; 
    let c: Vec<_> = 
     indices.iter() 
       .map(|index| { 
        *vec[*index] = *vec[*index] + 1.0; 
        *vec[*index] 
       }) 
       .collect(); 
    println!("{:?}", c); 
} 

[2, 3, 4]が正しく表示されます。

関連する問題