简体   繁体   English

取消引用弧<rwlock<t> &gt; 返回 RwLockReadGuard<t> 默认</t></rwlock<t>

[英]Deref a Arc<RwLock<T>> to return RwLockReadGuard<T> by default

I have the following wrapper for Arc<RwLock<T>> , and I would like to deref them to return the RwLockReadGuard<T> by default.我有以下Arc<RwLock<T>>包装器,我想取消它们以默认返回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()
        }
    }
}

I wrote the above wrapper mainly for the PartialEq I need for a parent struct to correctly #[derive(PartialEq)] .我主要为PartialEq编写了上面的包装器,我需要一个父结构来正确#[derive(PartialEq)]

Most of the time I'm reading the values T from Arc<RwLock<T>> , writing to it is rare.大多数时候,我从Arc<RwLock<T>>读取值T ,很少写入它。

The above implementation allows me to read/write the values using:上述实现允许我使用以下方式读取/写入值:

some_arc_object.write()?.uuid = Uuid::new_v4();
let updated_uuid: T = some_arc_object.read().uuid;
// where uuid is a field of T

Since I'm reading the properties most of the time, I'd like to get rid of the repeated .read() and achieve the following by Dereferencing the entire Arc<RwLock>:由于我大部分时间都在阅读属性,因此我想摆脱重复的.read()并通过取消引用整个 Arc<RwLock> 来实现以下目标:

let updated_uuid: T = some_arc_object.uuid;
// instead of having to add .read()
// let updated_uuid: T = some_arc_object.read().uuid;

My current humble attempt is shown above in the commented section, trying to make deref() work the same way .read() does.我目前的谦虚尝试显示在上面的评论部分,试图使deref()以与.read()相同的方式工作。 But the compiler is not happy with returning a reference of a local variable.但是编译器对返回局部变量的引用并不满意。 Is there any chance it could be achieved, either by some lifetime magic or other workaround?有没有可能通过一些终生的魔法或其他解决方法来实现它?

Dereferences by design should only resolve smart pointers to the pointee, see eg the Rust API Guidelines .通过设计取消引用应该只解析指向指针的智能指针,例如参见Rust API 指南 Acquiring a synchronization guard like MutexGuard or RwLockReadGuard in the Deref definitely goes beyond this guideline and could cause subtle bugs.Deref中获取诸如MutexGuardRwLockReadGuard之类的同步保护肯定超出了此准则,并可能导致细微的错误。 Ie you can get implicit locking of a resource without ever explicitly calling lock() , read() or write() on it because it's hidden in the Deref impl which implicitly gets called when resolving a method call.即你可以在没有显式调用lock()read()write()的情况下获得资源的隐式锁定,因为它隐藏在Deref impl 中,在解析方法调用时会隐式调用它。

As for the reasoning why it's not possible: Deref 's return type is a reference, thus you need to return something that you can turn into a reference from deref() .至于为什么不可能的原因: Deref的返回类型是一个引用,因此您需要返回一些可以从deref()转换为引用的东西。 The RwLockReadGuard is a value that you're creating inside the deref() scope, thus it's dropped at the end of the scope, which in turn means you're not allowed to hand out a reference to it. RwLockReadGuard是您在deref() scope 中创建的值,因此它在 scope 的末尾被删除,这反过来意味着您不允许分发对它的引用。

Sometimes it can be ergonomic to wrap whatever you need to do with the value inside the RwLock inside a function, ie if it's a String that sometimes gets written to but most of the time you just want to read it, define some convenience method like the following:有时,将 RwLock 中的值包含在RwLock中可能符合人体工程学,即,如果它是一个有时会被写入但大多数时候您只想阅读它的String ,请定义一些方便的方法,例如下列的:

struct Foo {
    shared: Arc<RwLock<String>>,
}
impl Foo {
    fn get_shared_str(&self) -> String {
        self.shared.read().unwrap().clone()
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM