可变借用互斥体内部的对象 - 如何重构? [英] Mutable borrow to object inside Mutex - how to refactor?

查看:51
本文介绍了可变借用互斥体内部的对象 - 如何重构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的许多功能中都有以下模式:

I have the following pattern in many of my functions:

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

struct State { 
    value: i32
}

fn foo(data: Arc<Mutex<State>>) {
    let state = &mut data.lock().expect("Could not lock mutex");
    // mutate `state`
}

&mut *data.lock().expect("Could not lock mutex") 一遍遍重复,所以想重构为一个函数,为了写类似的东西

&mut *data.lock().expect("Could not lock mutex") is repeated over and over, so I would like to refactor it to a function, in order to write something like

let state = get_state(data); 

我尝试了以下方法:

fn get_state(data: &Arc<Mutex<State>>) -> &mut State {
    &mut data.lock().expect("Could not lock mutex")
}

编译失败:

错误:无法返回引用临时值的值

ERROR: cannot return value referencing temporary value

这让我相信 data.state.lock().expect("...") 按值返回.但是,我可以看到状态通过多个 foo 调用在这个游乐场.

This makes me believe that data.state.lock().expect("...") returns by value. However, I can see the state being mutated through multiple foo calls on this playground.

这里发生了什么?为什么我这个看似简单的重构编译失败?

我希望以下内容也能正常工作:

I would expect the following to work as well:

fn get_state<'a>(data: &'a Arc<Mutex<State>>) -> &'a mut State {
    let state: &'a mut State = &mut data.lock().expect("Could not lock mutex");
    state
}

但它失败了:

   |
12 | fn get_state<'a>(data: &'a Arc<Mutex<State>>) -> &'a mut State {
   |              -- lifetime `'a` defined here
13 |     let state: &'a mut State = &mut data.lock().expect("Could not lock mutex");
   |                -------------        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
   |                |
   |                type annotation requires that borrow lasts for `'a`
14 |     state
15 | }
   | - temporary value is freed at the end of this statement

为什么从 lock 返回的生命周期与 data 参数之一不匹配?

Why doesn't the lifetime of whatever is returned from lock match the one of the data parameter?

推荐答案

lock() 方法返回 MutexGuard 而不是对受保护对象的直接引用.您可以使用对象引用,因为 MutexGuard 实现了 DerefDerefMut,但是您仍然需要 mutex-guard 在范围内,因为当它超出范围时,互斥锁将被释放.此外,对内部对象的引用的生命周期与互斥保护的生命周期绑定,因此编译器将不允许您在没有互斥保护的情况下使用对内部对象的引用.

The lock() method returns MutexGuard instead of a direct reference to the guarded object. You are able to work with object reference, because MutexGuard implements Deref and DerefMut, but you still need the mutex-guard to be in scope, because when it goes out of scope the mutex lock will be released. Also the lifetime of the reference to the iner object is bound to the lifetime of the mutex guard, so the compiler will not allow you to use the reference to the inner object without the mutex guard.

您可以在宏或方法中提取常用逻辑,但它应返回 MutexGuard 而不是对内部对象的引用.

You can extract your common logic in a macro or a method, but it should return MutexGuard instead of a reference to the inner object.

这篇关于可变借用互斥体内部的对象 - 如何重构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆