试图从 RwLock 返回引用,“借来的值不够长"错误 [英] Trying to return reference from RwLock, "borrowed value does not live long enough" Error

查看:22
本文介绍了试图从 RwLock 返回引用,“借来的值不够长"错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在做我的第一个 Rust 项目,但遇到了障碍.我正在使用 HashMapStrings 映射到 AtomicUsize 整数.HashMapRwLock 保护以允许并发访问.我希望能够在 HashMap 中返回对 AtomicUsize 值的引用,但是如果我尝试在 RwLockWriteGuard 的生命周期之后将这些引用返回给调用者 我收到一个错误,提示 借用值的寿命不够长.我在下面复制了一个最小示例并将相同的示例放在 Rust 游乐场 这里.

I've been working on my first Rust project recently but have hit a snag. I am using a HashMap mapping Strings to AtomicUsize integers. The HashMap is protected by a RwLock to allow for concurrent access. I would like to be able to return references to AtomicUsize values in the HashMap, however if I try to return these references to the caller past the lifetime of the RwLockWriteGuard I get an error that borrowed value does not live long enough. I've reproduced a minimal example below and put the same example on the Rust playground here.

use std::collections::HashMap;
use std::sync::RwLock;
use std::sync::atomic::{AtomicUsize, Ordering};

struct Bar {
    val: AtomicUsize
}

impl Bar {
    pub fn new() -> Self {
        Bar { val: AtomicUsize::new(0) }
    }
}

struct Foo {
    map: RwLock<HashMap<String, Bar>>
}


impl Foo {
    pub fn get(&self, key: String) -> &Bar {
        self.map.write().unwrap().entry(key).or_insert(Bar::new())
    }
}

fn main() {
    let foo = Foo {map: RwLock::new(HashMap::new())};
    let bar = foo.get("key".to_string());
}

我得到的错误发生在线路上:

The error I get occurs on the line:

self.map.write().unwrap().entry(key).or_insert(Bar::new())

而且是因为借来的价值的寿命不够长.我已经阅读了一些其他讨论这个错误的帖子,这个 one 尤其重要.读完之后,我可以得出从互斥锁返回的值的生命周期必须小于互斥锁的生命周期,这似乎完全排除了我正在尝试做的事情.我明白为什么这是不可能的,因为如果我们有一个指向 Hashmap 的指针,而另一个将值插入到互斥体中导致它被调整大小,那么我们将有一个悬空指针.

And is because the borrowed value does not live long enough. I've read a few other posts that discuss this error, this one in particular was especially relevant. After reading it over, I can gather that a value returned from a mutex must have a lifetime less than that of the mutex, which would seem to rule out completely what I'm trying to do. I can see why this should be impossible, because if we have a pointer into the Hashmap and another inserts values into the mutex which cause it to be resized, then we will have a dangling pointer.

那么,我的问题是双重的.首先,我只是好奇我是否正确理解了这个问题,或者是否还有其他原因导致我被禁止做我试图做的事情?我的第二个问题是,如果没有 Box 原子整数并将它们存储在 HashMap 中,是否还有另一种方法可以完成我想要做的事情?这种方法似乎对我有用,因为我们可以返回一个指向始终有效的 Boxed 值的指针.然而,这种方法似乎效率低下,因为它需要额外的指针间接层和额外的分配.谢谢!

My question, then, is twofold. Firstly, I'm just curious if I understand the problem correctly or if there is another reason why I'm disallowed from doing what I tried to do? And my second question is if there is perhaps another way to accomplish what I am trying to do without Box the atomic integers and storing those in the HashMap? Such an approach seems like it should work to me because we can return a pointer to the Boxed value which would always be valid. However it seems like this approach would be inefficient because it would require an extra layer of pointer indirection and an extra allocation. Thanks!

推荐答案

你是正确的,你不能返回对超过 MutexGuard 的东西的引用,因为这可能会导致悬空指针.

You're correct that you can't return a reference to something which outlives the MutexGuard, because that would lead to a possibly dangling pointer.

不过,将内容包装在 Box 中并没有帮助!Box 是一个拥有的指针,除了重定向之外,就引用生命周期而言,它的行为类似于包含的值.毕竟,如果您返回了对它的引用,其他人可能会将其从 HashMap 中删除并取消分配.

Wrapping the contents in a Box won't help, though! A Box is an owned pointer and apart from the redirection behaves like the contained value as far as reference lifetime goes. After all, if you returned a reference to it, someone else might remove it from the HashMap and de-allocate it.

根据您想对参考做什么,我可以想到几个选项:

Depending on what you want to do with the reference, I can think of a couple of options:

  1. 不要对值进行Box,而是将它们包装在Arc中.从 HashMap 中获取时,您将克隆 Arc,并且可以同时存在多个引用.

  1. Instead of Boxing the values, wrap them in Arc. You would clone the Arc when taking from the HashMap, and multiple references can live at the same time.

您也可以将 MutexGuard 连同引用一起返回;请参阅 this question,如果您只想对值进行操作然后相对较快地删除引用,这将很有效.这将使互斥锁保持不变,直到您完成它为止.

You could also return the MutexGuard along with the reference; see this question, which would work well if you just want to operate on the value and then drop the reference relatively soon. This would keep the mutex held until you're finished with it.

这篇关于试图从 RwLock 返回引用,“借来的值不够长"错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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