RwLockWriteGuard 和 RwLockReadGuard 在同一个变量中?

RwLockWriteGuard and RwLockReadGuard in same variable?

我目前正在实施一个多客户端键值存储(如 redis 或 memcached),它允许客户端获得对存储的独占访问权限。

现在我遇到的问题是,当从共享存储中获取值时,它可以由 RwLockWriteGoard(当独占访问处于活动状态时)或 RwLockReadGuard(当不处于活动状态时)保护。

我没有找到将存储保存在变量中以便稍后以不关心它是否受读保护或写保护保护的方式对其执行操作的方法。

这是我目前使用的简化解决方案。

// Assume Store is like this
let store = Arc::new(RwLock::new(HashMap::new()));

// --snip--
let mut exclusive_access: Option<RwLockWriteGuard<HashMap<String, String>>> = None;

while !is_finished {
    // --snip--
    let response = match parse_command(&command) {
        Command::Get(key) => {
            let read_result = match exclusive_access {
                Some(exclusive_store) => match exclusive_store.get(&key) {
                    Some(x) => Some(x.clone()),
                    None => None,
                },
                None => match store.read().unwrap().get(&key) {
                    Some(x) => Some(x.clone()),
                    None => None,
                },
            };

            // simplified
            read_result
        }
        // --snip--
    };

    if gain_exclusive_access {
        exclusive_access = Some(store.write().unwrap());
    } else {
        exclusive_access = None;
    }
}

如果可能的话,我想把 Command::Get(key) 的 arm 写成这样:

let store = match exclusive_access {
    Some(store) => store,
    None => store.read().unwrap()
};
store.get(&key)

但这不起作用,因为它的两个臂匹配 return 不同的类型(RwLockWriteGuard 和 RwLockReadGuard)。

有没有办法解决这个问题,我太盲目了,看不到?

使用枚举作为标记联合。

use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};

enum LockWrapper<'a, T>{
    Read(RwLockReadGuard<'a, T>),
    Write(RwLockWriteGuard<'a, T>)
}

impl<'a, T> Deref for LockWrapper<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self {
            LockWrapper::Read(read_guard) => read_guard.deref(),
            LockWrapper::Write(write_guard) => write_guard.deref()
        }
    }
}

fn main()  {
    let lock: RwLock<i32> = RwLock::new(0);
    let condition = false;
    let guard = match condition{
        true=>LockWrapper::Read(lock.read().unwrap()),
        false=>LockWrapper::Write(lock.write().unwrap())
    };
    // Now guard holds either read or write lock.

}