为什么不能将借记功能的静态哈希图借为可变的?

Net*_*ave 3 static mutable lifetime rust

我正在尝试在中创建一个备忘录功能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()
    }
}
Run Code Online (Sandbox Code Playgroud)

错误是:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么静态寿命参数不能可变?

hel*_*low 5

在Rust中,变量默认是不可变的,因此您不能对未声明为的变量进行突变mut。该'static终身不影响可变性,但是变量只生活了多久。

一个“[...],可以反复调用无变异的状态。” 。而这正是问题所在。您要更改环境(在本例中为)。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()
    }
}
Run Code Online (Sandbox Code Playgroud)

附带说明#[feature(nll)]一下,如果您使用错误消息编译代码实际上是非常好的。

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()
    }
}
Run Code Online (Sandbox Code Playgroud)