Rust中mem_swap空向量后绑定结果至自身的优势探究
先看这段Carboxyl库中的代码实现:
impl<A: Send + Sync + Clone + 'static> Source<A> { /// Make the source send an event to all its observers. pub fn send(&mut self, a: A) { use std::mem; let mut new_callbacks = vec!(); mem::swap(&mut new_callbacks, &mut self.callbacks); self.callbacks = new_callbacks .into_iter() .filter_map(|mut callback| { let result = callback(a.clone()); match result { Ok(_) => Some(callback), Err(_) => None, } }) .collect(); } }
这种先swap再处理的方式,比直接对self.callbacks执行filter_map后重新赋值,有以下几个实际优势:
规避借用冲突风险
如果直接操作self.callbacks,迭代过程中会持有该向量的可变引用。要是回调函数callback内部存在间接访问self.callbacks的逻辑(比如递归调用send方法),就会触发Rust的借用检查错误。而swap之后,self.callbacks被置为空,我们操作的是独立的new_callbacks,原容器的可变引用被释放,彻底避免了这类编译或运行时的借用冲突。优化内存使用效率
swap过来的空向量new_callbacks,在后续collect时可以复用其内存容量。相比直接用self.callbacks.into_iter().collect()的方式,原向量的内存空间被转移到new_callbacks中处理,处理完成后再赋值回self.callbacks,能减少不必要的内存分配与释放操作,尤其在回调数量较多时,性能提升更明显。确保迭代的一致性与完整性
若直接遍历self.callbacks,如果回调执行过程中有其他逻辑修改了这个向量(比如外部并发操作,或者回调内部的间接修改),会导致迭代器失效,引发panic或遍历结果异常。swap之后,我们处理的是一个独立的向量副本(实际是原向量的所有权转移),此时self.callbacks为空,不会被任何外部操作干扰,能保证所有原始回调都被完整执行一次,不会出现漏执行或重复执行的问题。
内容的提问来源于stack exchange,提问作者lighthouse

