我有一个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
个对象。我可以迭代对象并附加每个元素,但考虑到我在超出范围之前清除它的值,是否有更有效的方法?
答案 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(..));