默认将 Arc<RwLock<T>> 取消引用到 return RwLockReadGuard<T>
Deref a Arc<RwLock<T>> to return RwLockReadGuard<T> by default
我有以下 Arc<RwLock<T>>
的包装器,我想默认将它们取消引用 return RwLockReadGuard<T>
。
use anyhow::{Result, bail};
use serde::{Deserialize, Serialize};
use std::ops::Deref;
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ArcRwLock<T: Sized>(Arc<RwLock<T>>);
impl<T> ArcRwLock<T> {
pub fn new(data: T) -> Self {
ArcRwLock(Arc::new(RwLock::new(data)))
}
pub fn write(&self) -> Result<RwLockWriteGuard<T>> {
match self.0.try_write() {
Ok(x) => Ok(x),
Err(e) => {
bail!(
"RwLock cannot acquire writer lock, error: {}",
e.to_string()
)
}
}
}
pub fn read(&self) -> RwLockReadGuard<T> {
self.0.read().unwrap()
}
}
// impl<T: Sized> Deref for ArcRwLock<T> {
// type Target = RwLockReadGuard<T>;
// #[inline]
// fn deref(&self) -> &Self::Target {
// self.0.read().unwrap()
// }
// }
impl<T: PartialEq> PartialEq for ArcRwLock<T> {
fn eq(&self, other: &Self) -> bool {
if Arc::ptr_eq(&self.0, &other.0) && ::core::ptr::eq(&*self.0, &*other.0) {
true
} else {
*other.0.read().unwrap().deref() == *self.0.read().unwrap().deref()
}
}
}
我写上面的包装器主要是为了 PartialEq
我需要一个正确的父结构 #[derive(PartialEq)]
.
大部分时间我从Arc<RwLock<T>>
读取值T
,很少写入。
以上实现允许我 read/write 使用以下值:
some_arc_object.write()?.uuid = Uuid::new_v4();
let updated_uuid: T = some_arc_object.read().uuid;
// where uuid is a field of T
因为我大部分时间都在阅读属性,所以我想摆脱重复的 .read()
并通过取消引用整个 Arc 来实现以下目标:
let updated_uuid: T = some_arc_object.uuid;
// instead of having to add .read()
// let updated_uuid: T = some_arc_object.read().uuid;
我目前的拙劣尝试显示在上面的评论部分,试图让 deref()
以与 .read()
相同的方式工作。但是编译器对 returning 局部变量的引用不满意。有没有可能通过一些终生魔法或其他解决方法实现它?
设计取消引用应该只解析指向指针的智能指针,参见例如Rust API Guidelines。在 Deref
中获得像 MutexGuard
或 RwLockReadGuard
这样的同步保护肯定超出了这个指导方针,并且可能会导致细微的错误。 IE。您可以获得资源的隐式锁定,而无需显式调用 lock()
、read()
或 write()
,因为它隐藏在 Deref
impl 中,它在解析方法时隐式调用打电话。
至于推理为什么是不可能的:Deref
的return类型是一个参考,因此你需要return您可以从 deref()
转换为参考的东西。 RwLockReadGuard
是您在 deref()
范围内创建的值,因此它被丢弃在范围的末尾,这反过来意味着您不允许分发对它的引用。
有时,将您需要对 RwLock
中的值进行的任何操作包装在一个函数中可能符合人体工学,即如果它是一个 String
有时会被写入但大多数时候你只是想阅读它,定义一些像下面这样的方便方法:
struct Foo {
shared: Arc<RwLock<String>>,
}
impl Foo {
fn get_shared_str(&self) -> String {
self.shared.read().unwrap().clone()
}
}
我有以下 Arc<RwLock<T>>
的包装器,我想默认将它们取消引用 return RwLockReadGuard<T>
。
use anyhow::{Result, bail};
use serde::{Deserialize, Serialize};
use std::ops::Deref;
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ArcRwLock<T: Sized>(Arc<RwLock<T>>);
impl<T> ArcRwLock<T> {
pub fn new(data: T) -> Self {
ArcRwLock(Arc::new(RwLock::new(data)))
}
pub fn write(&self) -> Result<RwLockWriteGuard<T>> {
match self.0.try_write() {
Ok(x) => Ok(x),
Err(e) => {
bail!(
"RwLock cannot acquire writer lock, error: {}",
e.to_string()
)
}
}
}
pub fn read(&self) -> RwLockReadGuard<T> {
self.0.read().unwrap()
}
}
// impl<T: Sized> Deref for ArcRwLock<T> {
// type Target = RwLockReadGuard<T>;
// #[inline]
// fn deref(&self) -> &Self::Target {
// self.0.read().unwrap()
// }
// }
impl<T: PartialEq> PartialEq for ArcRwLock<T> {
fn eq(&self, other: &Self) -> bool {
if Arc::ptr_eq(&self.0, &other.0) && ::core::ptr::eq(&*self.0, &*other.0) {
true
} else {
*other.0.read().unwrap().deref() == *self.0.read().unwrap().deref()
}
}
}
我写上面的包装器主要是为了 PartialEq
我需要一个正确的父结构 #[derive(PartialEq)]
.
大部分时间我从Arc<RwLock<T>>
读取值T
,很少写入。
以上实现允许我 read/write 使用以下值:
some_arc_object.write()?.uuid = Uuid::new_v4();
let updated_uuid: T = some_arc_object.read().uuid;
// where uuid is a field of T
因为我大部分时间都在阅读属性,所以我想摆脱重复的 .read()
并通过取消引用整个 Arc
let updated_uuid: T = some_arc_object.uuid;
// instead of having to add .read()
// let updated_uuid: T = some_arc_object.read().uuid;
我目前的拙劣尝试显示在上面的评论部分,试图让 deref()
以与 .read()
相同的方式工作。但是编译器对 returning 局部变量的引用不满意。有没有可能通过一些终生魔法或其他解决方法实现它?
设计取消引用应该只解析指向指针的智能指针,参见例如Rust API Guidelines。在 Deref
中获得像 MutexGuard
或 RwLockReadGuard
这样的同步保护肯定超出了这个指导方针,并且可能会导致细微的错误。 IE。您可以获得资源的隐式锁定,而无需显式调用 lock()
、read()
或 write()
,因为它隐藏在 Deref
impl 中,它在解析方法时隐式调用打电话。
至于推理为什么是不可能的:Deref
的return类型是一个参考,因此你需要return您可以从 deref()
转换为参考的东西。 RwLockReadGuard
是您在 deref()
范围内创建的值,因此它被丢弃在范围的末尾,这反过来意味着您不允许分发对它的引用。
有时,将您需要对 RwLock
中的值进行的任何操作包装在一个函数中可能符合人体工学,即如果它是一个 String
有时会被写入但大多数时候你只是想阅读它,定义一些像下面这样的方便方法:
struct Foo {
shared: Arc<RwLock<String>>,
}
impl Foo {
fn get_shared_str(&self) -> String {
self.shared.read().unwrap().clone()
}
}