我想写一个简单的回忆录函数.

fn memoize<K: Eq + Hash, V: Clone>(mut func: impl FnMut(&K) -> V) -> impl FnMut(K) -> V {
  let mut cache = HashMap::new();
  |key| {
    cache
      .entry(key)
      .or_insert_with_key(|k| func(k))
      .clone()
  }
}

Eq + Hash的参数范围似乎合理,但Clone的返回值似乎是不必要的.理想情况下,签名应为:

fn memoize<K: Eq + Hash, V>(mut func: impl FnMut(&K) -> V) -> impl FnMut(K) -> &mut V

这需要指定返回引用的生存期(这是有意义的).

理想情况下,&mut V应该在引用函数的生命周期内一直存在(或类似的情况:&'a mut impl FnMut(K) -> &'a mut V)

由于FN特征的隐含是不稳定的,如果我想留在FN特征中(不是用大约fn call(&'a mut self, key: K) -> &'a mut V个来写我的 struct ),有没有办法在稳定 rust 蚀中做到这一点?

推荐答案

不幸的是,这是不可能的.即使手动实现FnMut,这也是不可能的,除非我们将Output设置为泛型关联类型:

pub trait GatifiedFnMut<Args: std::marker::Tuple> {
    type Output<'a>
    where
        Self: 'a;
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output<'_>;
}

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

impl<K: Eq + Hash, V, F: FnMut(&K) -> V> GatifiedFnMut<(K,)> for Memoized<K, V, F> {
    type Output<'a> = &'a mut V
    where
        Self: 'a;
    extern "rust-call" fn call_mut(&mut self, (key,): (K,)) -> Self::Output<'_> {
        self.cache.entry(key).or_insert_with_key(&mut self.func)
    }
}

(Note:即使没有GATS也可以解决这个问题,但不能使用当前的FnOnce/FnMut/Fn特性,或者至少非常不舒服,参见下面的链接问题).

More information can be found at users.rust-lang.org.

Rust相关问答推荐

如何将元素添加到向量并返回对该元素的引用?

交叉术语未正确清除屏幕

使用Py03从Rust调用Python函数时的最佳返回类型

Trait bound i8:来自u8的不满意

JSON5中的变量类型(serde)

如果变量本身不是None,如何返回;如果没有,则返回None&Quot;?

根据填充系数以相对大小在给定空间中布局项目

获取已知数量的输入

如何获取光标下的像素 colored颜色 ?

如何限制 GtkColumnView 行数

方法可以被误认为是标准特性方法

Rust 为什么被视为borrow ?

trait 对象指针的生命周期

是否可以预测堆栈溢出?

为什么指定生命周期让我返回一个引用?

当我在 struct 中存储异步函数时,为什么它需要生命周期

当用作函数参数时,不强制执行与绑定的关联类型

如何为枚举中的单个或多个值返回迭代器

在 Rust 中枚举字符串的最佳方式? (字符()与 as_bytes())

`if let` 只是另一种编写其他 `if` 语句的方式吗?