【问题标题】:Deref coercion with generics使用泛型解除强制强制
【发布时间】:2017-07-02 06:19:21
【问题描述】:

我正在尝试编写一个参数化函数if_found_update 来更新哈希中的值(如果存在):

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(&amp;mut h, &amp;"A".to_string(), &amp;one, &amp;update); 工作正常,但 if_found_update(&amp;mut h, k, &amp;one, &amp;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`

我认为这是因为它无法进行适当的解除引用强制。有没有办法让这样的事情起作用?

【问题讨论】:

    标签: generics rust dereference


    【解决方案1】:

    HashMap 的一些方法,即getcontains_keyget_mutremove,可以接收借用的密钥类型。他们通过使用 Borrow 特征来做到这一点。它们在类型参数Q 上是通用的,可以是任何可以表示借用键的类型。它是这样工作的:当X 实现Borrow&lt;Y&gt; 时,这意味着&amp;X 可以作为&amp;Y 借用。例如String implements Borrow&lt;str&gt;,所以&amp;String可以借用为&amp;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));
    }
    

    【讨论】:

    • 谢谢!我试过Borrow,但我没有正确使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多