2017-06-30 19 views
1

我想實現類似的東西來HashMap::entry但允許不消耗鍵(見this RFC有類似的目的)。這裏是我的代碼,該IndeximplHashMap藍本(見thisthis)。如何實現一個類似於不使用密鑰的HashMap :: entry的函數?

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] 
    } 
} 

這給了我以下錯誤。

error[E0053]: method `get_or_insert` has an incompatible type for trait 
    --> src/main.rs:15:42 
    | 
6 |   fn get_or_insert(&mut self, key: &Q, value: V) -> &V; 
    |           -- type in trait 
... 
15 |   fn get_or_insert(&mut self, key: &Q, value: V) -> &V { 
    |           ^^ expected reference, found type parameter 
    | 
    = note: expected type `fn(&mut std::collections::HashMap<K, V, S>, &&'a Q, V) -> &V` 
       found type `fn(&mut std::collections::HashMap<K, V, S>, &Q, V) -> &V` 

這裏有什麼問題,我該如何解決?

我認爲會出現的另一個問題是,編譯器不知道Q::OwnedK。如果是這樣,我們該如何處理?

回答

3

我也是一個相對的初學者,但是從我所看到的有三個問題:

MapExt<&'a Q, V> 

應該

MapExt<Q, V> 

否則你改變你的特質的類型一個參考。

Q: Eq + Hash + ToOwned, 

應該明確的是

Q: Eq + Hash + ToOwned<Owned=K>, 

,以便它知道什麼類型的to_owned()返回。

self[key] 

應該

&self[key] 
+0

雖然這個工作,只是要小心,我不能告訴你,如果有更好的方法完全是因爲我太學:P – loganfsmyth

+0

謝謝,這與Shepmaster的回答結合清除我的理解。一個問題:我不知道「已有的」語法 - 它何時適用?只針對類型特徵?任何參考將有所幫助。 –

+0

顯式設置「ToOwned」特徵的「關聯類型」是語法。如果你看看https://doc.rust-lang.org/std/borrow/trait.ToOwned.html,你可以看到'Owned'是'to_owned'的返回值的類型。 – loganfsmyth

2

你的問題可以簡化爲這樣:

trait Alpha<A> { 
    fn alpha(&self, key: &A); 
} 

impl<'a, A> Alpha<&'a A> for() { 
    fn alpha(&self, key: &'a A) {} 
} 

基本上,你的混爲一談泛型類型。使用單獨的字母使得它更清晰:

impl<'a, B> Alpha<&'a B> for() {} 

也就是說,AlphaA值實際上是一個&'a B。然後這個特質說它需要參考這個值。一個有效的實現將是:

impl<'a, B> Alpha<&'a B> for() { 
    fn alpha(&self, key: &&'a B) {} 
} 

一旦你明白這一點,你可以按照loganfsmyth's points來解決與執行遺留問題。

+0

謝謝,這有幫助。 –

相關問題