2017-04-02 51 views
2

我对Rust很新,无法理解这个令人困惑的错误。当模式匹配一​​个选项时引发与不兼容类型的匹配错误引发的错误

我只是试图匹配Option返回的get函数HashMap。如果返回值,我想增加它,如果没有,我想添加一个新的元素到地图。

下面是代码:

let mut map = HashMap::new(); 
map.insert("a", 0); 
let a = "a"; 
match map.get(&a) { 
    Some(count) => *count += 1, 
    None => map.insert(a, 0), 
} 

产生的错误:

error[E0308]: match arms have incompatible types 
    --> <anon>:7:5 
    | 
7 |  match map.get(&a) { 
    | _____^ starting here... 
8 | |   Some(count) => *count += 1, 
9 | |   None => map.insert(a, 0), 
10 | |  } 
    | |_____^ ...ending here: expected(), found enum `std::option::Option` 
    | 
    = note: expected type `()` 
       found type `std::option::Option<{integer}>` 
note: match arm with an incompatible type 
    --> <anon>:9:17 
    | 
9 |   None => map.insert(a, 0), 
    |     ^^^^^^^^^^^^^^^^ 

我真的不知道该编译器抱怨什么类型的约在这里,因为这两个SomeNone是两部分相同的枚举类型。任何人都可以解释编译器与我的代码有什么问题吗?

回答

3

编译器引用的是匹配手臂机构返回的值,而不是每个匹配手臂的模式类型。

Some(count) => *count += 1, 
None => map.insert(a, 0), 

表达*count += 1计算结果为()(称为“单元”,在防锈,在许多其他语言“空隙”)。另一方面,表达式map.insert(a, 0)返回Option<V>,其中V是哈希映射的值类型(在您的情况下是整数)。突然,错误消息确实让一些感觉:

= note: expected type `()` 
= note: found type `std::option::Option<{integer}>` 

我想你甚至不想从match块返回的东西(记住:match块表情,太,所以你可以从它返回的东西)。要放弃任何表达式的结果,可以将其转换为;的语句。让我们试试这个:

match map.get(&a) { 
    Some(count) => { 
     *count += 1; 
    } 
    None => { 
     map.insert(a, 0); 
    } 
} 

每场比赛臂体是块现在({}之间的事情),每个块包含一个声明。请注意,我们技术上不需要更改第一个匹配部分,因为*count += 1已经返回(),但这种方式更一致。


但是,一旦你测试了这个,将会显示与借用有关的另一个错误。这是一个众所周知的问题,详细解释如下:here。总之:借检查是不是足够聪明,认识到你的代码是正确的,因此,你应该使用超好看entry-API

let map = HashMap::new(); 
map.insert("a", 0); 
let a = "a"; 
*map.entry(&a).or_insert(0) += 1; 
+1

感谢你,非常完美! 我会多看看'entry' API,它看起来非常有用。 –