Rust测试场景下创建模拟`sink`遇到的所有权与生命周期问题
错误原因
两个编译错误均源于所有权与借用规则冲突:
get_sink闭包内创建的sink是栈上局部变量,将其引用存入外层sinks后,sink会被移动到返回的闭包中,局部变量的引用会直接变为悬垂引用,不符合Rust生命周期约束。- 代码先对
sink做不可变借用存入sinks,随后又将sink所有权移动到返回的闭包中,同一时间存在不可变借用和可变使用,违反借用规则。
方案说明
你提到的用共享智能指针的思路完全正确,需要配合内部可变性容器实现需求:
- 串行场景下使用
Rc<RefCell<Vec<i32>>>即可,无需拆分两种类型,所有持有者都可通过borrow_mut()修改内部值,borrow()读取内部值。 - 若后续要适配rayon并行场景,将
Rc<RefCell>替换为线程安全的Arc<Mutex<Vec<i32>>>即可,不需要修改func_under_test的核心逻辑。
串行场景可运行代码
use std::rc::Rc; use std::cell::RefCell; fn func_under_test<GetSink, F>( mut get_sink: GetSink ) where GetSink: FnMut(usize) -> F, F: FnMut(i32) -> (), { let idxs : Vec<usize> = (0..2).collect(); idxs.iter().for_each(|&i| { let mut sink = get_sink(i); sink(0i32); sink(1i32); sink(2i32); }); } fn main() { let mut sinks : Vec<Rc<RefCell<Vec<i32>>>> = vec![]; let get_sink = |i: usize| { let sink = Rc::new(RefCell::new(Vec::new())); sinks.push(sink.clone()); move |x : i32| { sink.borrow_mut().push(x); } }; func_under_test(get_sink); assert_eq!(*sinks[0].borrow(), vec![0i32, 1i32, 2i32]); assert_eq!(*sinks[1].borrow(), vec![0i32, 1i32, 2i32]); }
并行场景适配代码
替换智能指针类型即可兼容rayon并行逻辑:
use std::sync::{Arc, Mutex}; fn func_under_test<GetSink, F>( mut get_sink: GetSink ) where GetSink: FnMut(usize) -> F + Send, F: FnMut(i32) -> () + Send, { // 此处直接换成rayon的par_iter即可正常并行运行 let idxs : Vec<usize> = (0..2).collect(); idxs.iter().for_each(|&i| { let mut sink = get_sink(i); sink(0i32); sink(1i32); sink(2i32); }); } fn main() { let mut sinks : Vec<Arc<Mutex<Vec<i32>>>> = vec![]; let get_sink = |i: usize| { let sink = Arc::new(Mutex::new(Vec::new())); sinks.push(sink.clone()); move |x : i32| { sink.lock().unwrap().push(x); } }; func_under_test(get_sink); assert_eq!(*sinks[0].lock().unwrap(), vec![0i32, 1i32, 2i32]); }
该实现完全兼容你的使用场景:测试环境下用向量存储结果做断言,生产环境只需修改get_sink的实现返回写文件的闭包,无需调整func_under_test的核心逻辑。
内容的提问来源于stack exchange,提问作者Harry Braviner
相关产品推荐
相关产品推荐

