You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

稳定版Rust中如何实现返回引用的memoize函数?

稳定版Rust中实现无Clone约束记忆化函数的方案

首先明确:仅依靠标准库的Fn/FnMut trait,稳定版Rust无法实现你想要的签名。原因在于标准FnMut的call_mut方法签名限制:

pub trait FnMut<Args>: FnOnce<Args> {
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

这里的Self::Output是一个关联类型,无法与&mut self的生命周期绑定,所以闭包无法返回一个和自身内部缓存绑定的可变引用。

如果不想依赖不稳定特性,同时要避免Clone约束,唯一可行的方式是自定义结构体来封装缓存和闭包,而非使用匿名闭包。以下是具体实现:

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

struct Memoized<K, V, F> {
    cache: HashMap<K, V>,
    func: F,
}

impl<K: Eq + Hash, V, F: FnMut(&K) -> V> Memoized<K, V, F> {
    fn new(func: F) -> Self {
        Self {
            cache: HashMap::new(),
            func,
        }
    }

    fn call(&'_ mut self, key: K) -> &'_ mut V {
        self.cache.entry(key).or_insert_with_key(|k| (self.func)(k))
    }
}

// 辅助函数创建实例
fn memoize<K: Eq + Hash, V, F: FnMut(&K) -> V>(func: F) -> Memoized<K, V, F> {
    Memoized::new(func)
}

使用方式示例:

fn main() {
    let mut compute = memoize(|k: &i32| k * 2);
    let val1 = compute.call(3);
    *val1 += 1;
    assert_eq!(*compute.call(3), 7);
}

如果你坚持想要用闭包风格的返回值(即impl FnMut(K) -> &mut V),稳定版Rust暂时做不到——因为闭包的输出类型无法携带自身的生命周期。只能等待Fn trait的关联类型生命周期稳定(比如FnMut的Output支持依赖调用时的self生命周期),或者接受上述自定义结构体的方案。

内容的提问来源于stack exchange,提问作者Link0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 13:40:24