2017-02-14 91 views
3

我想寫一個參數化功能if_found_update如果存在的話,在哈希更新的值:DEREF強制使用泛型

use std::collections::HashMap; 

fn if_found_update<K, V>(data: &mut HashMap<K, V>, k: &K, v: &V, f: &Fn(&V, &V) -> V) -> bool 
    where K: std::cmp::Eq, 
      K: std::hash::Hash 
{ 
    if let Some(e) = data.get_mut(k) { 
     *e = f(e, v); 
     return true; 
    } 
    false 
} 

fn main() { 
    let mut h: HashMap<String, i64> = HashMap::new(); 
    h.insert("A".to_string(), 0); 
    let one = 1 as i64; 
    fn update(e1: &i64, e2: &i64) -> i64 { 
     e1 + e2 
    }; 
    let k: &str = &"A".to_string(); 
    println!("{}", 
      if_found_update(&mut h, &"A".to_string(), &one, &update)); // works 
    println!("{}", if_found_update(&mut h, k, &one, &update)); // fails to compile 
} 

if_found_update(&mut h, &"A".to_string(), &one, &update);工作正常,但if_found_update(&mut h, k, &one, &update)失敗,編譯:

error[E0308]: mismatched types 
    --> src/main.rs:24:44 
    | 
24 |  println!("{}", if_found_update(&mut h, k, &one, &update)); // fails to compile 
    |           ^expected struct `std::string::String`, found str 
    | 
    = note: expected type `&std::string::String` 
    = note: found type `&str` 

我認爲這是因爲它沒有適當的deref強制。有沒有辦法讓這樣的事情發揮作用?

回答

7

一些HashMap的方法,即getcontains_keyget_mutremove,可接收的鍵類型的一個借用版本。他們通過使用Borrow這個特性來做到這一點。它們是通用類型參數Q,它可以是任何可以表示借用密鑰的類型。它以這種方式工作:當X執行Borrow<Y>時,這意味着&X可以作爲&Y借用。例如,String implements Borrow<str>,所以&String可以作爲&str借用。

您可以通過在函數中引入額外的類型參數並添加正確的邊界來利用此優勢。

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

fn if_found_update<K, V, Q>(data: &mut HashMap<K, V>, k: &Q, v: &V, f: &Fn(&V, &V) -> V) -> bool 
    where K: Hash + Eq + Borrow<Q>, 
      Q: ?Sized + Hash + Eq 
{ 
    if let Some(e) = data.get_mut(k) { 
     *e = f(e, v); 
     return true; 
    } 
    false 
} 

fn main() { 
    let mut h: HashMap<String, i64> = HashMap::new(); 
    h.insert("A".to_string(), 0); 
    let one = 1 as i64; 
    fn update(e1: &i64, e2: &i64) -> i64 { e1 + e2 } 
    let k: &str = "A"; 
    println!("{}", if_found_update(&mut h, &"A".to_string(), &one, &update)); 
    println!("{}", if_found_update(&mut h, k, &one, &update)); 
} 
+0

謝謝!我嘗試過'借用',但我沒有正確使用它。 – divbyzero