如何在不克隆结构体的情况下过滤MutexGuard中的Vector?
Rust中不克隆结构体过滤MutexGuard内Vector的解决方案
你遇到的问题是:持有已锁定的MutexGuard<A>,其中A包含Vec<B>,想在不克隆B的前提下过滤这个Vector,但原代码触发了cannot move out of dereference of MutexGuard<'_, A>错误。
错误原因
原代码中a.b.into_iter()会尝试将Vec<B>的所有权从MutexGuard包裹的A中移走,但此时a是对MutexGuard的可变借用,Rust的借用规则禁止在持有可变引用时移走内部字段——这会导致MutexGuard指向的结构体处于无效状态,违反内存安全。
正确实现方式
推荐使用Vec::retain方法,它会在原Vector上直接修改,保留满足条件的元素,无需移动整个Vector的所有权,完美适配MutexGuard的借用规则:
use std::sync::{Arc, Mutex}; #[derive(Debug)] struct B { n: i64, } #[derive(Debug)] struct A { b: Vec<B> } fn main() { let arc_a = Arc::new(Mutex::new(A { b: vec![ B { n: 1 }, B { n: 2 }, B { n: 3 }, B { n: 4 }, ] })); let mut a = arc_a.lock().unwrap(); // retain直接在原Vec上过滤,保留奇数n的B实例 a.b.retain(|b| b.n % 2 == 1); println!("{:?}", a); }
另一种可选方案:通过swap转移所有权
如果需要更灵活的处理(比如过滤后还要对原Vector做其他操作),可以用std::mem::swap临时转移Vector的所有权,过滤后再换回去:
use std::sync::{Arc, Mutex}; use std::mem; #[derive(Debug)] struct B { n: i64, } #[derive(Debug)] struct A { b: Vec<B> } fn main() { let arc_a = Arc::new(Mutex::new(A { b: vec![ B { n: 1 }, B { n: 2 }, B { n: 3 }, B { n: 4 }, ] })); let mut a = arc_a.lock().unwrap(); // 临时转移Vec所有权到temp let mut temp = Vec::new(); mem::swap(&mut a.b, &mut temp); // 过滤temp,得到新的Vec let filtered = temp.into_iter().filter(|b| b.n % 2 == 1).collect(); // 将过滤后的Vec放回a.b mem::swap(&mut a.b, &mut filtered); println!("{:?}", a); }
这种方式也不会克隆B,但相比retain代码更繁琐,仅在需要对原Vector做额外处理时使用。
内容的提问来源于stack exchange,提问作者Vladimir Alinsky
相关产品推荐
相关产品推荐

