在Rust中创建HashMap <i32,i32 =“”>

时间:2017-01-02 08:59:40

标签: rust

在尝试使用Rust解决LeetCode问题时,我遇到了一个奇怪的问题:看起来我无法使用基本类型创建HashMap

use std::collections::HashMap;

fn two_sum(nums: &Vec<i32>, target: i32) -> (usize, usize) {
    let mut map = HashMap::new();
    for (i, x) in nums.iter().enumerate() {
        match map.get(target - x) {
            Some(k) => return (k, i),
            None => map.insert(x, i)
        };
    }
    return (0, 0);
}

fn main() {
    let ret = two_sum(&vec![1,2,3], 4);
    println!("{}, {}", ret.0, ret.1);
}

编译器抱怨:

error[E0308]: mismatched types
 --> two_sum.rs:6:23
  |
6 |         match map.get(target - x) {
  |                       ^^^^^^^^^^ expected reference, found i32
  |
  = note: expected type `&_`
  = note:    found type `i32`

error[E0308]: mismatched types
 --> two_sum.rs:7:32
  |
7 |             Some(k) => return (k, i),
  |                                ^ expected usize, found reference
  |
  = note: expected type `usize`
  = note:    found type `&_`

是否有必要始终在Rust中使用HashMap的引用?

编辑:

看起来有必要......解决方案看起来有点难看但无论如何都有效。

use std::collections::HashMap;

fn two_sum(nums: &[i32], target: i32) -> (usize, usize) {
    let mut map = HashMap::new();
    for (i, x) in nums.iter().enumerate() {
        let df = target - x;
        if map.contains_key(&df) {
            return (*map.get(&df).unwrap(), i);
        }
        map.insert(x, i);
    }
    return (0, 0);
}

fn main() {
    let ret = two_sum(&vec![1,2,3], 4);
    println!("{}, {}", ret.0, ret.1);
}

我想知道是否有更好的解决方案或一些最佳实践来使用具有原始类型的HashMaps?

1 个答案:

答案 0 :(得分:6)

如果您检查get方法的签名,您将意识到:

  • 它接受以&Q
  • 为界的K: Borrow<Q>, Q: Hash + Eq参数
  • 返回Option<&V>

因此,虽然哈希映射本身将包含基元,但get接口需要引用并返回引用。

这意味着:

fn two_sum(nums: &Vec<i32>, target: i32) -> (usize, usize) {
    let mut map = HashMap::new();
    for (i, x) in nums.iter().enumerate() {
        match map.get(&(target - x)) {
            //        ^~~~~~~~~~~~~
            Some(k) => return (*k as usize, i),
            //                 ^~~~~~~~~~~
            None => map.insert(x, i)
        };
    }
    return (0, 0);
}

我(1)传递对get的引用,(2)取消引用我得到的结果(并将其从i32转换为usize)。

但是,这还不起作用,因为map.get(&a)map块的持续时间内借用map,因此您无法插入其中。通过在match块之后移动插入来解决这个问题:

fn two_sum(nums: &Vec<i32>, target: i32) -> (usize, usize) {
    let mut map = HashMap::new();
    for (i, x) in nums.iter().enumerate() {
            let a = target - x;
            match map.get(&a) {
                Some(k) => return (*k as usize, i),
                None => (),
            };
            map.insert(x, i);
    }
    return (0, 0);
}

就是这样。具有基元类型的Hashmap

旁注:与其他一些语言不同,原始类型与Rust中的其他类型几乎无法区分。