返回引用的返回函数

Lin*_*nk0 6 rust

我想写一个简单的记忆功能。

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

Eq + Hash对参数的约束似乎是合理的,但Clone对返回值的约束似乎是不必要的。理想情况下的签名是:

fn memoize<K: Eq + Hash, V>(mut func: impl FnMut(&K) -> V) -> impl FnMut(K) -> &mut V
Run Code Online (Sandbox Code Playgroud)

这需要指定返回引用的生命周期(有意义)。

理想情况&mut V下,只要函数的引用存在,它就应该存在(或者类似的东西&'a mut impl FnMut(K) -> &'a mut V:)

由于 Fn 特征的 impls 不稳定,如果我想留在 Fn 特征内(而不是用 some 编写我的结构fn call(&'a mut self, key: K) -> &'a mut V),有没有办法在稳定的 Rust 中做到这一点?

Cha*_*man 1

不幸的是,这是不可能的。即使手动实现也是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)
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:即使没有 GAT,也可以解决这个问题,但不能使用当前的FnOnce//特征,或者至少非常不舒服,请参阅下面链接的问题)FnMutFn

更多信息可以在 users.rust-lang.org 找到