Rust中如何在if/else分支从引用生成MappedRwLockWriteGuard?
解决parking_lot中RwLock引用与映射守卫类型不匹配的问题
方案一:用ManuallyDrop包装映射守卫转换类型
通过ManuallyDrop阻止MappedRwLockWriteGuard自动解锁,再将其转为普通&mut引用,让两个分支类型统一:
use parking_lot::{RwLock, MappedRwLockWriteGuard}; use std::mem::ManuallyDrop; // 示例类型定义 struct MyStruct { property: MyReference, } type MyReference = i32; fn main() { let my_lock = RwLock::new(MyStruct { property: 0 }); let mut simple_mut_reference_to_property = &mut 1; let i_already_have_the_reference = true; let property: &mut MyReference = if i_already_have_the_reference { simple_mut_reference_to_property } else { let guard = my_lock.write(); let mapped_guard = guard.map(|v| &mut v.property); // 包装后避免自动解锁 let mut manually_drop_guard = ManuallyDrop::new(mapped_guard); // 转为普通可变引用 &mut *manually_drop_guard }; // 使用property *property += 1; }
注意:此方案需要你手动确保else分支的锁在合适时机释放,否则会导致锁长期持有。
方案二:使用手动加锁/解锁API
parking_lot提供了类似C风格的手动锁控制API,直接调用lock()和unlock()相关逻辑:
use parking_lot::RwLock; // 示例类型定义 struct MyStruct { property: MyReference, } type MyReference = i32; fn main() { let my_lock = RwLock::new(MyStruct { property: 0 }); let mut simple_mut_reference_to_property = &mut 1; let i_already_have_the_reference = true; let (property, lock_guard) = if i_already_have_the_reference { (simple_mut_reference_to_property, None) } else { let guard = my_lock.write(); let prop = &mut guard.property; (prop, Some(guard)) }; // 使用property *property += 1; // 手动释放锁(仅当持有锁时) drop(lock_guard); }
通过将锁守卫和引用绑定返回,确保锁在不需要时被正确释放,同时统一了两个分支的返回类型。
方案三:自定义无操作守卫类型
你提到的创建虚拟守卫的思路可行,自定义一个实现DerefMut的类型,drop时不执行解锁操作:
use parking_lot::{RwLock, MappedRwLockWriteGuard}; use std::ops::{Deref, DerefMut}; // 自定义无操作守卫 struct DummyGuard<'a, T>(&'a mut T); impl<'a, T> Deref for DummyGuard<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } impl<'a, T> DerefMut for DummyGuard<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } // 示例类型定义 struct MyStruct { property: MyReference, } type MyReference = i32; fn main() { let my_lock = RwLock::new(MyStruct { property: 0 }); let mut simple_mut_reference_to_property = &mut 1; let i_already_have_the_reference = true; let property: Box<dyn DerefMut<Target = MyReference>> = if i_already_have_the_reference { Box::new(DummyGuard(simple_mut_reference_to_property)) } else { Box::new(my_lock.write().map(|v| &mut v.property)) }; // 使用property *property += 1; }
此方案会引入动态分发开销,对性能敏感场景建议优先选择前两种方案。
内容的提问来源于stack exchange,提问作者Amin Ya
相关产品推荐
相关产品推荐

