在递归上下文中访问可变缓存

问题描述 投票:0回答:1

我有以下代码

fn foo(value: &String, cache: &mut HashMap<String, Vec<String>>) {
    // values are inserted but never modified
    cache.insert("a", vec!["b".to_string()]);
    if let Some(cached_result) = cache.get(value) {
        // let cached_result = cached_result.clone();
        cached_result
            .iter()
            .for_each(|cached_value| foo(cached_value, cache));
    }
}

这是我试图理解的问题的最小化且完全人为的示例。

在上面的代码中,借用检查器抱怨:

error[E0500]: closure requires unique access to `*cache` but it is already borrowed
 --> src/day11.rs:8:23
  |
4 |     if let Some(cached_result) = cache.get(value) {
  |                                  ----- borrow occurs here
...
8 |             .for_each(|cached_value| foo(cached_value, cache));
  |              -------- ^^^^^^^^^^^^^^                   ----- second borrow occurs due to use of `*cache` in closure
  |              |        |
  |              |        closure construction occurs here
  |              first borrow later used by call

我的理解是这样的

  • cache
    拥有其价值观的所有权
  • 理论上我们可以修改
    cached_result
    下游,因此我们无法在迭代它的同时安全地将其传递到那里

问题是,在我的实际代码中,我从不修改值,我只插入到缓存中。

克隆

cached_result
解决了问题,但我不想这样做。

我应该如何构建代码,以便我可以拥有一个内部包含不可变值的可变缓存,并且能够在迭代该值时使用该缓存?

rust
1个回答
0
投票

我的建议是使用原子引用计数器(

Arc
),这样就可以避免真正的克隆,而是增加对内存中相同数据点的引用计数器。

因为您实际上只是阅读,这应该足够了,并且可以避免数据克隆的性能损失。为了提高线程之间的安全性,您可以在

Mutex
中引入
Arc
,但您可能不需要它。

根据您的概念片段,代码可能如下所示:

use std::{collections::HashMap, sync::Arc};

fn foo(value: &String, cache: &mut HashMap<String, Arc<Vec<String>>>) {
    // values are inserted but never modified
    cache.insert("a".into(), Arc::new(vec!["b".to_string()]));
    if let Some(cached_result) = cache.get(value) {
        cached_result.clone()
            .iter()
            .for_each(|cached_value| foo(cached_value, cache));
    }
}

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.