如何实现类似于 HashMap::entry 且不消耗密钥的函数?

r.v*_*r.v 2 generics traits rust

我正在尝试实现类似的东西,HashMap::entry但不允许使用密钥(请参阅具有类似目的的RFC )。Index impl这是我的代码,以for为模型HashMap(参见thisthis)。

use std::collections::HashMap;
use std::hash::{Hash, BuildHasher};
use std::borrow::Borrow;

trait MapExt<Q: ?Sized, V> {
    fn get_or_insert(&mut self, key: &Q, value: V) -> &V;
}

impl<'a, Q: ?Sized, K, V, S> MapExt<&'a Q, V> for HashMap<K, V, S>
where
    K: Eq + Hash + Borrow<Q>,
    Q: Eq + Hash + ToOwned,
    S: BuildHasher,
{
    fn get_or_insert(&mut self, key: &Q, value: V) -> &V {
        if !self.contains_key(key) {
            self.insert(key.to_owned(), value);
        }
        self[key]
    }
}
Run Code Online (Sandbox Code Playgroud)

这给了我以下错误。

use std::collections::HashMap;
use std::hash::{Hash, BuildHasher};
use std::borrow::Borrow;

trait MapExt<Q: ?Sized, V> {
    fn get_or_insert(&mut self, key: &Q, value: V) -> &V;
}

impl<'a, Q: ?Sized, K, V, S> MapExt<&'a Q, V> for HashMap<K, V, S>
where
    K: Eq + Hash + Borrow<Q>,
    Q: Eq + Hash + ToOwned,
    S: BuildHasher,
{
    fn get_or_insert(&mut self, key: &Q, value: V) -> &V {
        if !self.contains_key(key) {
            self.insert(key.to_owned(), value);
        }
        self[key]
    }
}
Run Code Online (Sandbox Code Playgroud)

这里出了什么问题以及如何修复它?

我认为会出现的另一个问题是编译器不知道是否Q::OwnedK。如果确实如此,我们该如何处理?

log*_*yth 5

我也是一个相对初学者,但据我所知,存在三个问题:

MapExt<&'a Q, V>
Run Code Online (Sandbox Code Playgroud)

应该

MapExt<Q, V>
Run Code Online (Sandbox Code Playgroud)

否则,您将把特征类型更改为参考。

Q: Eq + Hash + ToOwned,
Run Code Online (Sandbox Code Playgroud)

应该明确地是

Q: Eq + Hash + ToOwned<Owned=K>,
Run Code Online (Sandbox Code Playgroud)

这样它就知道to_owned()将返回什么类型。

self[key]
Run Code Online (Sandbox Code Playgroud)

应该

&self[key]
Run Code Online (Sandbox Code Playgroud)