模式匹配选项时引用具有不兼容类型的匹配臂时引发错误 [英] Error thrown citing match arms with incompatible types when pattern matching an Option

查看:39
本文介绍了模式匹配选项时引用具有不兼容类型的匹配臂时引发错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 Rust 还很陌生,无法理解这个令人困惑的错误.

I am fairly new to Rust and cannot get my head around this confusing error.

我只是想匹配 HashMapget 函数返回的 Option.如果返回一个值,我想增加它,否则我想向地图添加一个新元素.

I am simply trying to match on an Option returned by the get function of a HashMap. If a value is returned I want to increment it, if not I want to add a new element to the map.

代码如下:

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 都是同一个枚举类型的一部分.谁能解释编译器对我的代码有什么问题?

I am not really sure what types the compiler is complaining about here, as both Some and None are both part of the same enum type. Can anyone explain what issue the compiler is having with my code?

推荐答案

编译器指的是匹配臂体返回的值,而不是每个匹配臂的模式类型.

The compiler is referring to the value the match arm bodies return, not the type of the pattern of each match arm.

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

表达式 *count += 1 的计算结果为 ()(在 Rust 中称为unit",在许多其他语言中称为void").另一方面,表达式 map.insert(a, 0) 返回 Option 其中 V 是哈希映射的值类型(在您的情况下为整数).突然间,错误消息确实有点意思:

The expression *count += 1 evaluates to () (called "unit" in Rust, "void" in many other languages). The expression map.insert(a, 0) on the other hand returns Option<V> where V is the value type of the hash map (an integer in your case). Suddenly the error message does make some sense:

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

我想你甚至不想从 match 块中返回一些东西(记住:match 块也是表达式,所以你可以从中返回一些东西).要丢弃任何表达式的结果,您可以使用 ; 将其转换为语句.让我们试试这个:

I suppose you don't even want to return something from the match block (remember: match blocks are expressions, too, so you could return something from it). To discard the result of any expression, you can convert it to a statement with ;. Let's try this:

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

每个匹配臂体现在都是一个块(介于 {} 之间)并且每个块包含一个语句.请注意,从技术上讲,我们不需要更改第一个匹配臂,因为 *count += 1 已经返回 (),但这种方式更加一致.

Each match arm body is a block now (something between { and }) and each block contains one statement. Note that we technically don't need to change the first match arm, as *count += 1 already returns (), but this way it's more consistent.

但是一旦您对此进行测试,就会显示另一个与借用相关的错误.这是一个众所周知的问题,并进行了更详细的解释 这里.简而言之:借用检查器不够聪明,无法识别您的代码是好的,因此您应该使用超级好的 entry-API:

But once you test this, another error related to borrowing will be shown. This is a well known issue and is explained in more detail here. In short: the borrow checker is not smart enough to recognize that your code is fine and therefore you should use the super nice entry-API:

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

这篇关于模式匹配选项时引用具有不兼容类型的匹配臂时引发错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆