无法将互斥体中的向量附加到另一个向量

时间:2016-08-31 09:58:25

标签: rust mutex

我有一个myfunc :: (Int -> Bool) -> (Int -> Int) -> [Int] -> [Int] myfunc _ _ [] = [] myfunc ce ao (x : xs) = if ce x then ao x : tail else tail where tail = myfunc ce ao xs 对象,它通过Vec<String>在线程之间共享。我想取其当前值并将其附加到其他地方的另一个向量然后清除它:

Arc<Mutex>

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(); } 无效,因为extend实际上是lines_result个对象。我可以迭代对象并附加每个元素,但考虑到我在超出范围之前清除它的值,是否有更有效的方法?

3 个答案:

答案 0 :(得分:8)

您可以use Vec::drain()将其所有内容移出到迭代器中,这样您就可以在.extend()中使用它,同时清除原始矢量。

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

答案 1 :(得分:7)

您可以使用Vec::append()将所有元素从一个向量移动到另一个向量的末尾。

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

答案 2 :(得分: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>>`

正如您所说,MutexGuard不是Iterator。大多数情况下,即当您在其上调用方法时,可以使用MutexGuard<T>代替T,因为它实现了Deref<T>,编译器将自动取消引用需要时。

因此,一种选择是明确取消引用:

store.lines.extend(&*lines_result);

这(部分)有效,因为&*lines_result是对实施Vec的基础IntoIterator的引用。但是,我认为调用iter方法更具惯用性和明确性(这实际上是编译器将对IntoIterator执行的操作:

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

然而,这仍然没有编译,因为这个迭代器返回对内容的引用,而不是实际的String。所以我们可以通过要求克隆它们来解决这个问题:

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

这样做有效,但效率低下 - 它在String中分配了每个Vec的新副本,就在丢弃原件之前。这是(正如另一个答案所说的)Vec::drain()的确切含义;它将移动 Vec的部分或全部项目到一个新的迭代器中,它产生值(不是引用)。 v.drain(..)(使用..全范围)一次性完成所有这些操作,并给出最终结果:

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