Rust 中带有 RwLockGuard 的 HashMap 记录游标
Cursor of HashMap records with RwLockGuard in Rust
我是 Rust 的新手,我正在尝试使用 RwLock
中受保护的 HashMap
来实现一个简单的、线程安全的内存键值存储。我的代码如下所示:
use std::sync::{ Arc, RwLock, RwLockReadGuard };
use std::collections::HashMap;
use std::collections::hash_map::Iter;
type SimpleCollection = HashMap<String, String>;
struct Store(Arc<RwLock<SimpleCollection>>);
impl Store {
fn new() -> Store { return Store(Arc::new(RwLock::new(SimpleCollection::new()))) }
fn get(&self, key: &str) -> Option<String> {
let map = self.0.read().unwrap();
return map.get(&key.to_string()).map(|s| s.clone());
}
fn set(&self, key: &str, value: &str) {
let mut map = self.0.write().unwrap();
map.insert(key.to_string(), value.to_string());
}
}
到目前为止,这段代码工作正常。问题是我正在尝试实现一个 scan()
函数,其中 returns 一个 Cursor
对象,可用于遍历所有记录。我希望 Cursor
对象持有一个 RwLockGuard
,它在游标本身被释放之前不会被释放(基本上我不想在 Cursor 存在时允许修改)。
我试过这个:
use ...
type SimpleCollection = HashMap<String, String>;
struct Store(Arc<RwLock<SimpleCollection>>);
impl Store {
...
fn scan(&self) -> Cursor {
let guard = self.0.read().unwrap();
let iter = guard.iter();
return Cursor { guard, iter };
}
}
struct Cursor<'l> {
guard: RwLockReadGuard<'l, SimpleCollection>,
iter: Iter<'l, String, String>
}
impl<'l> Cursor<'l> {
fn next(&mut self) -> Option<(String, String)> {
return self.iter.next().map(|r| (r.0.clone(), r.1.clone()));
}
}
但这没有用,因为我遇到了这个编译错误:
error[E0597]: `guard` does not live long enough
--> src/main.rs:24:20
|
24 | let iter = guard.iter();
| ^^^^^ borrowed value does not live long enough
25 | return Cursor { guard, iter };
26 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 22:5...
--> src/main.rs:22:5
|
22 | / fn scan(&self) -> Cursor {
23 | | let guard = self.0.read().unwrap();
24 | | let iter = guard.iter();
25 | | return Cursor { guard, iter };
26 | | }
| |_____^
有什么想法吗?
如评论中所述,问题是。您尝试构建的 Cursor
结构包含 MutexGuard
和借用 MutexGuard
的迭代器,这是不可能的(有充分的理由 - 请参阅链接的问题)。
在这种情况下,最简单的解决方法是引入一个单独的结构来存储 MutexGuard
,例如
struct StoreLock<'a> {
guard: RwLockReadGuard<'a, SimpleCollection>,
}
在Store
上,我们可以引入一个返回StoreLock
的方法
fn lock(&self) -> StoreLock {
StoreLock { guard: self.0.read().unwrap() }
}
和 StoreLock
可以公开实际的 scan()
方法(可能还有其他需要持久锁的方法):
impl<'a> StoreLock<'a> {
fn scan(&self) -> Cursor {
Cursor { iter: self.guard.iter() }
}
}
Cursor
结构本身只包含迭代器:
struct Cursor<'a> {
iter: Iter<'a, String, String>,
}
客户端代码首先需要获取锁,然后获取游标:
let lock = s.lock();
let cursor = lock.scan();
这可确保锁的寿命足以完成扫描。
我是 Rust 的新手,我正在尝试使用 RwLock
中受保护的 HashMap
来实现一个简单的、线程安全的内存键值存储。我的代码如下所示:
use std::sync::{ Arc, RwLock, RwLockReadGuard };
use std::collections::HashMap;
use std::collections::hash_map::Iter;
type SimpleCollection = HashMap<String, String>;
struct Store(Arc<RwLock<SimpleCollection>>);
impl Store {
fn new() -> Store { return Store(Arc::new(RwLock::new(SimpleCollection::new()))) }
fn get(&self, key: &str) -> Option<String> {
let map = self.0.read().unwrap();
return map.get(&key.to_string()).map(|s| s.clone());
}
fn set(&self, key: &str, value: &str) {
let mut map = self.0.write().unwrap();
map.insert(key.to_string(), value.to_string());
}
}
到目前为止,这段代码工作正常。问题是我正在尝试实现一个 scan()
函数,其中 returns 一个 Cursor
对象,可用于遍历所有记录。我希望 Cursor
对象持有一个 RwLockGuard
,它在游标本身被释放之前不会被释放(基本上我不想在 Cursor 存在时允许修改)。
我试过这个:
use ...
type SimpleCollection = HashMap<String, String>;
struct Store(Arc<RwLock<SimpleCollection>>);
impl Store {
...
fn scan(&self) -> Cursor {
let guard = self.0.read().unwrap();
let iter = guard.iter();
return Cursor { guard, iter };
}
}
struct Cursor<'l> {
guard: RwLockReadGuard<'l, SimpleCollection>,
iter: Iter<'l, String, String>
}
impl<'l> Cursor<'l> {
fn next(&mut self) -> Option<(String, String)> {
return self.iter.next().map(|r| (r.0.clone(), r.1.clone()));
}
}
但这没有用,因为我遇到了这个编译错误:
error[E0597]: `guard` does not live long enough
--> src/main.rs:24:20
|
24 | let iter = guard.iter();
| ^^^^^ borrowed value does not live long enough
25 | return Cursor { guard, iter };
26 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 22:5...
--> src/main.rs:22:5
|
22 | / fn scan(&self) -> Cursor {
23 | | let guard = self.0.read().unwrap();
24 | | let iter = guard.iter();
25 | | return Cursor { guard, iter };
26 | | }
| |_____^
有什么想法吗?
如评论中所述,问题是Cursor
结构包含 MutexGuard
和借用 MutexGuard
的迭代器,这是不可能的(有充分的理由 - 请参阅链接的问题)。
在这种情况下,最简单的解决方法是引入一个单独的结构来存储 MutexGuard
,例如
struct StoreLock<'a> {
guard: RwLockReadGuard<'a, SimpleCollection>,
}
在Store
上,我们可以引入一个返回StoreLock
fn lock(&self) -> StoreLock {
StoreLock { guard: self.0.read().unwrap() }
}
和 StoreLock
可以公开实际的 scan()
方法(可能还有其他需要持久锁的方法):
impl<'a> StoreLock<'a> {
fn scan(&self) -> Cursor {
Cursor { iter: self.guard.iter() }
}
}
Cursor
结构本身只包含迭代器:
struct Cursor<'a> {
iter: Iter<'a, String, String>,
}
客户端代码首先需要获取锁,然后获取游标:
let lock = s.lock();
let cursor = lock.scan();
这可确保锁的寿命足以完成扫描。