如何从Arc包装的Hashmap和Rust包装的Mutex返回对值的引用?
我在返回如何从Arc包装的Hashmap和Rust包装的Mutex返回对值的引用?,rust,Rust,我在返回HashMap中的值引用时遇到了一些麻烦,该值由Arc和Mutex包装,用于在线程之间共享。代码如下所示: 使用std::sync::{Arc,Mutex}; 使用std::collections::HashMap; 结构嘿{ a:弧形 } 恳求嘿{ fn获取(&self,键:&String)->&String{ self.a.lock().unwrap().get(key.unwrap()) } } 如上所示,代码未能编译,因为返回一个引用当前函数所拥有的数据的值。我知道lock(
HashMap
中的值引用时遇到了一些麻烦,该值由Arc和Mutex包装,用于在线程之间共享。代码如下所示:
使用std::sync::{Arc,Mutex};
使用std::collections::HashMap;
结构嘿{
a:弧形
}
恳求嘿{
fn获取(&self,键:&String)->&String{
self.a.lock().unwrap().get(key.unwrap())
}
}
如上所示,代码未能编译,因为
返回一个引用当前函数所拥有的数据的值。我知道lock()
返回一个局部变量MutexGuard。但是我如何实现这种方法来获取HashMap中的值的引用呢。如果我不能,生锈的动机是什么?您需要克隆弧并将克隆弧移动到另一个线程/任务。从克隆中,您可以锁定并访问它。如果访问多于写入,我建议使用RwLock
而不是互斥锁
克隆弧时,不是克隆基础对象,而是克隆弧。同样,在您的情况下,您需要将结构包装成圆弧或更改设计,因为应该克隆和移动的是圆弧
我相信分享物品的方法应该是通过警卫。使用RWLock,多人可通过防护装置读取地图:
use async_std::task;
use std::sync::{Arc,RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::collections::HashMap;
#[derive(Default)]
struct Hey{
a:Arc<RwLock<HashMap<String, String>>>
}
impl Hey {
pub fn read(&self) -> RwLockReadGuard<'_, HashMap<String, String>> {
self.a.read().unwrap()
}
pub fn write(&self) -> RwLockWriteGuard<'_, HashMap<String, String>> {
self.a.write().unwrap()
}
}
fn main() {
let h = Hey{..Default::default()};
h.write().insert("k1".to_string(), "v1".to_string());
println!("{:?}", h.read().get("k1"));
task::block_on(async move {
println!("{:?}", h.read().get("k1"));
});
}
使用async_std::task;
使用std::sync::{Arc、RwLock、RwLockReadGuard、rwlockriteguard};
使用std::collections::HashMap;
#[衍生(默认)]
结构嘿{
a:弧形
}
impl Hey{
pub fn read(&self)->RwLockReadGuard{
self.a.write().unwrap()
}
}
fn main(){
设h=Hey{..Default::Default()};
h、 write().插入(“k1.to_string(),“v1.to_string());
println!(“{:?}”,h.read().get(“k1”);
任务::块打开(异步移动){
println!(“{:?}”,h.read().get(“k1”);
});
}
让我解释一下为什么rustc认为您的代码是错误的
只有在锁定了互斥锁保护的值时,才能与该值进行交互
由RAII guard操作的锁
所以,我要删除你的代码:
fn get(&self,key:&String)->&String{
让lock=self.a.lock().unwrap();
let reference=lock.get(key.unwrap();
放下(锁);//释放你的锁
//我们返回对不受互斥保护的数据的引用!
//有人可以从hashmap中删除项目,您将读取已删除的数据
//免费后使用是UB,所以禁止
返回参考;
}
您可能需要使用弧
作为值:
#[derive(Default)]
struct Hey{
a:Arc<RwLock<HashMap<String, Arc<String>>>>
}
fn get(&self,key:&String)->Arc<String>{
self.a.lock().unwrap().get(key).unwrap().clone()
}
#[派生(默认)]
结构嘿{
a:弧形
}
fn get(&self,key:&String)->Arc{
self.a.lock().unwrap().get(key.unwrap().clone())
}
附言。
另外,您可以使用Arc
(我建议这样做),这样可以避免额外的指针间接指向。它可以从字符串中构建:let-arc:arc=my_String.into()
或Arc::from(my_string)
如果允许该返回类型指向互斥锁的数据内部,则不会阻止其他代码锁定互斥锁并删除条目,这意味着返回的引用将指向已解除分配的内容。@loganfsmyth是的,您是对的。如果允许的话,地图可能会因为来自另一个线程的操作而改变,它是UB。我想你没听清我的话。编译错误是因为Mutex
中的lock()
返回一个临时变量,其生存期属于get
函数的范围。因此它不能返回引用。现在,这并不是由于线程的原因,我相信使用getfn-ref到hashmap,然后将inside-ref返回到string;相反,我分享了我找到守卫的方法。这将允许同时阅读,因为这是很好的!假设读一次,然后忘记这种操作。然而,这里关于一致性的假设是,获取hashmap值的引用(字符串的Arc克隆)的线程可以一直指向hashmap中不再存在的值。i、 另一个线程可以改变映射,并在hashmap中放置另一个弧。