2016-08-31 3 views
2

Arc<Mutex>でスレッド間で共有されているVec<String>オブジェクトがあります。私は、現在の値を取得し、別の場所で別のベクトルにそれを追加し、それをクリアしたい:ベクトルをミューテックスに別のベクトルに追加できません

use std::thread; 
use std::sync::{Arc, Mutex}; 

struct Store { 
    lines: Vec<String> 
} 

fn main() { 
    let mut store = Store { lines: vec![] }; 

    let lines = Arc::new(Mutex::new(vec!["Initial value".to_string()])); 
    let lines_clone = lines.clone(); 

    let t2 = thread::spawn(move || { 
     // populate lines 
    }); 

    let t1 = thread::spawn(move || { 
     let mut lines_result = lines_clone.lock().unwrap(); 
     store.lines.extend(lines_result); // This will not work 
     lines_result.clear(); 
    }); 

    let _ = t1.join(); 
    let _ = t2.join(); 
} 

extendlines_resultが実際にMutexGuardオブジェクトであるため、機能しません。オブジェクト全体を反復して各要素を追加できますが、範囲外になる前に値をクリアしていると考えると、より効率的な方法がありますか?

+0

あなたはまた、:: 'MEMを使用して置き換えることができます(&MUT * lines_result、Vecを::新しい())'移動することが'&mut'の後ろからベクトルを取り出し、それを空のものに置き換えます。 – sellibitze

答えて

8

use Vec::drain()あなたはすべてのコンテンツをイテレータに移動することができますので、.extend()でそれを使用して、元のベクトルをクリアすることができます。

move || { 
    let mut lines_result = lines_clone.lock().unwrap(); 
    store.lines.extend(lines_result.drain(..)); 
} 
7

あなたは別の終わりに1つのベクトルからすべての要素を移動するためにVec::append()を使用することができます。

store.lines.append(&mut lines_clone.lock().unwrap()); 
3

はエラーを見ると、あなたが得る:

error: the trait bound `std::sync::MutexGuard<'_, std::vec::Vec<std::string::String>>: std::iter::Iterator` is not satisfied [--explain E0277] 
    --> <anon>:20:21 
    |> 
20 |>   store.lines.extend(lines_result); // This will not work 
    |>      ^^^^^^ 
note: `std::sync::MutexGuard<'_, std::vec::Vec<std::string::String>>` is not an iterator; maybe try calling `.iter()` or a similar method 
note: required because of the requirements on the impl of `std::iter::IntoIterator` for `std::sync::MutexGuard<'_, std::vec::Vec<std::string::String>>` 

あなたが言うように、MutexGuardIteratorではありません。多くの場合、つまりメソッドを呼び出すときには、を実装しているので、Tの代わりにMutexGuard<T>を使用することができ、コンパイラは必要なときに自動的に参照解除します。

だから1つのオプションであることが明示的に間接参照:

store.lines.extend(&*lines_result); 

この&*lines_resultIntoIteratorを実装している下位Vecへの参照は、あるので、(一部)動作します。しかし、私は、コンパイラはIntoIteratorで何をするか効果的である(それはより多くの慣用的だと思うとiterメソッドを呼び出すためにクリア:このイテレータは、コンテンツへの参照を返すよう

store.lines.extend(lines_result.iter()); 

しかし、これはまだコンパイルされません、ではない実際のString Sだから我々はあまりにもクローニングすることにそれらを求めることにより、この問題を回避できます。

store.lines.extend(lines_result.iter().cloned()); 

そして、これは動作しますが、非効率的である - それはちょうど前に、Vecに各Stringの新しいコピーを割り当てています。とにかくオリジナルを破棄します。別の答えは言った)まったくVec::drain()のためのものです; の項目の一部またはすべてを(参照ではなく)値を生成する新しいイテレータに移動します。 v.drain(..)..フルレンジを使用して)最終的に与えて、一度にそれらのすべてを取る:

store.lines.extend(lines_result.drain(..)); 
関連する問題