【问题标题】:How to impl ops::Deref for an struct wrapped in a Mutex如何为包裹在互斥锁中的结构实现 ops::Deref
【发布时间】:2021-07-16 05:07:15
【问题描述】:

当为结构使用Arc<Mutex<>> 包装器时,是否可以将包装器解引用到内部结构字段之一中?在这种情况下,我想将我的 PersonWrapper 结构体从内部 PersonStruct“名称”字段中转换为 String

use std::sync::{Mutex, Arc};

pub struct PersonWrapper{
  inner: Arc<Mutex<Person>>
}

impl PersonWrapper{
    pub fn new(name: String, age: i32,)->Self{
        PersonWrapper{
            inner: Arc::new(Mutex::new(Person::new(name, age)))
        }
    }
}

pub struct Person{
    name: String,
    age: i32, 
}

impl Person{
    pub fn new(name: String, age: i32)->Self{
        Person{
            name,
            age,
        }
    }
}

impl std::ops::Deref for PersonWrapper{
    type Target = String;

    fn deref(&self) -> &Self::Target {
        &self.inner.into_inner().unwrap().name
        // &self.inner.lock().unwrap().node_id.clone()
    }
}


fn main(){
  let wrapped_person = PersonWrapper::new(String::from("Zondo"), 45);
  assert_eq!(*wrapped_person, String::from("Zondo"));
}

给出错误:

error[E0515]: cannot return reference to temporary value
           &self.inner.into_inner().unwrap().name
            ^--------------------------------^^^^^
            ||
            |temporary value created here
            returns a reference to data owned by the current function

error[E0507]: cannot move out of an `Arc`
            &self.inner.into_inner().unwrap().name
             ^^^^^^^^^^ move occurs because value has type `Mutex<Person>`, which does not implement the `Copy` trait

Playground

【问题讨论】:

  • 忽略Arc/Mutex 问题,将Deref 用于Person 的名称中,我认为是滥用该特征。目前尚不清楚为什么一个人应该表现得好像它是一个字符串并允许像person.is_empty()这样的东西。
  • 我明白了。我想我以前见过这样使用它,但在这种情况下这可能没有意义。我只是希望能够轻松访问name 字段。

标签: rust


【解决方案1】:

如果您需要方便地访问Mutex 后面的部分数据,结合锁定和“投影”(缩小到一个字段),您可以使用parking_lot 包中的Mutex。在许多其他优化和改进中,它提供了MutexGuard。例如:

use std::sync::Arc;
use parking_lot::{Mutex, MutexGuard, MappedMutexGuard};

pub struct PersonWrapper {
    inner: Arc<Mutex<Person>>,
}

impl PersonWrapper {
    pub fn new(name: String, age: i32) -> Self {
        PersonWrapper {
            inner: Arc::new(Mutex::new(Person::new(name, age))),
        }
    }
    
    pub fn name(&self) -> MappedMutexGuard<String> {
        MutexGuard::map(self.inner.lock(), |p| &mut p.name)
    }
}

现在您可以使用name(),就好像它是一个锁定的互斥体,只保留了Personname 部分:

let wrapped_person = PersonWrapper::new("Zondo".to_owned(), 45);
assert_eq!(&*wrapped_person.name(), "Zondo");
*wrapped_person.name() = "Mondo".to_owned();
assert_eq!(&*wrapped_person.name(), "Mondo");

Playground

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2020-05-29
    • 2011-07-20
    相关资源
    最近更新 更多