为什么不能将用于记忆函数的静态散列图借用为可变的?

Why cant a static hashmap for a memoizing function be borrowed as mutable?

我正在尝试在 Rust 中创建一个记忆功能。获取缓存 HashMap 的可变引用时会出现问题。我对类型系统仍然没有信心,我有点挣扎。

use std::collections::HashMap;
use std::hash::Hash;

fn memoize<A, B, F>(f: F, cache: &'static HashMap<A, B>) -> impl Fn(A) -> B
where
    A: Eq + Hash + Copy,
    B: Clone,
    F: Fn(A) -> B,
{
    move |value: A| {
        if !cache.contains_key(&value) {
            cache.insert(value, f(value.clone()));
        }
        let res = cache.get(&value).unwrap();
        res.clone()
    }
}

错误是:

error[E0596]: cannot borrow immutable borrowed content `**cache` as mutable
  --> src/lib.rs:12:13
   |
12 |             cache.insert(value, f(value.clone()));
   |             ^^^^^ cannot borrow as mutable

为什么静态生命周期参数不能可变?

在 Rust 中,默认情况下变量是不可变的,因此您不能改变未声明为 mut 的变量。 'static lifetime 不会影响可变性,只会影响变量的寿命。

A Fn [...] 可以重复调用而不改变状态。。而这正是问题所在。您想改变环境(在本例中是您的 HashMap)。

您必须使用 FnMut 才能改变环境。

如果你使用Entry API,你可以简化你的代码:

use std::collections::HashMap;
use std::hash::Hash;

fn memoize<A, B, F>(f: F, cache: &'static mut HashMap<A, B>) -> impl FnMut(A) -> B
where
    A: Eq + Hash + Copy,
    B: Clone,
    F: Fn(A) -> B,
{
    move |value: A| {
        let res = cache.entry(value).or_insert_with(|| f(value));
        res.clone()
    }
}

作为旁注,如果您使用 #[feature(nll)] 编译代码,错误消息实际上非常好。

error[E0596]: cannot borrow `*cache` as mutable, as `Fn` closures cannot mutate their captured variables
  --> src/lib.rs:14:13
   |
14 |             cache.insert(value, f(value.clone()));
   |             ^^^^^ cannot borrow as mutable
   |
help: consider changing this to accept closures that implement `FnMut`