返回对 Arc 和 Mutex 后面的值的可变引用

Ref*_*ker 5 rust

pub struct ForesterViewModel {
    m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}

impl ForesterViewModel {
    pub fn new() -> ForesterViewModel {
        ForesterViewModel {
            m_tree_lines: Arc::new(Mutex::new(vec![])),
        }
    }

    pub fn get_the_forest(&mut self) -> &mut Vec<TreeLine> {
        ???????????????????????????????
    }
}
Run Code Online (Sandbox Code Playgroud)

我需要帮助编写该get_the_forest函数。我尝试了很多不同的方法,但它们都返回编译错误。我需要返回一个可变引用,Vec<TreeLine>该引用被包装在self.m_tree_lines.

Dou*_*oug 4

没有办法做到这一点。

您创建一个具体MutexGuard对象,当您调用时释放互斥锁lock;您不能将引用移出包含防护的范围:

pub fn as_mut(&mut self) -> &Whatever {
  let mut guard = self.data.lock().unwrap();
  Ok(guard.deref())
  drop(guard) // <--- implicitly added here, which would invalidate the ref
}
Run Code Online (Sandbox Code Playgroud)

由于更复杂的原因(基本上 rust 无法表达这一点),您不能同时返回互斥锁保护和引用,出于同样的原因,它不能在单个结构中拥有引用和对象;请参阅有关为什么我不能在同一结构中存储值和对该值的引用的讨论?

...所以基本上你最好的选择是两件事之一:

/// Return the mutex guard itself
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
    Ok(self.m_tree_lines.lock()?)
}
Run Code Online (Sandbox Code Playgroud)
/// Pass a function in, which patches the mutable internal value
pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
    let mut guard = self.m_tree_lines.lock()?;
    patch(&mut guard); // <-- patch happens while guard is still alive
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

完整代码:

use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::PoisonError;
use std::error::Error;
use std::fmt;
use std::fmt::Formatter;
use std::ops::Deref;

#[derive(Debug, Copy, Clone)]
pub enum TreeLockError {
    FailedToLock
}

impl Error for TreeLockError {}

impl fmt::Display for TreeLockError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl<T> From<PoisonError<T>> for TreeLockError {
    fn from(_: PoisonError<T>) -> Self {
        TreeLockError::FailedToLock
    }
}

// ---

#[derive(Debug)]
pub struct TreeLine {
    pub value: &'static str
}

pub struct ForesterViewModel {
    m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}

impl ForesterViewModel {
    pub fn new() -> ForesterViewModel {
        ForesterViewModel {
            m_tree_lines: Arc::new(Mutex::new(vec![])),
        }
    }

    pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
        Ok(self.m_tree_lines.lock()?)
    }
    
    pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
        let mut guard = self.m_tree_lines.lock()?;
        patch(&mut guard);
        Ok(())
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let mut vm = ForesterViewModel::new();
    
    {
        let mut trees = vm.get_the_forest()?;
        trees.push(TreeLine{ value: "one"});
        trees.push(TreeLine{ value: "two"});
    } // <--- Drop the mutable reference here so you can get it again later
    
    // Patch
    vm.patch_forest(|trees| {
        trees.push(TreeLine{ value: "three"}); 
    });
    
    // ...
    let trees = vm.get_the_forest()?;
    println!("{:?}", trees.deref());
    
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

2862 次

最近记录:

3 年,6 月 前