gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 04:51:52 26 4
gpt4 key购买 nike

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> {
???????????????????????????????
}
}

我需要帮助编写 get_the_forest功能。我尝试过很多不同的东西,但它们都返回编译错误。我需要返回对 Vec<TreeLine> 的可变引用在 self.m_tree_lines 中包裹在 Arc 和 Mutex 后面.

最佳答案

没有办法做到这一点。

您创建了一个具体的 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
}

不能同时返回互斥保护和引用,原因更复杂(基本上 rust 不能表达),同样的原因它不能在单个结构中有引用和对象;查看关于 Why can't I store a value and a reference to that value in the same struct? 的讨论

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

/// Return the mutex guard itself
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
Ok(self.m_tree_lines.lock()?)
}
/// 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(())
}

完整代码:

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(())
}

关于rust - 返回对 Arc 和 Mutex 后面的值的可变引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66726259/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com