2017-02-14 116 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