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

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

问题描述

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

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

我只是试图匹配 HashMap get 函数返回的 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),
   |                 ^^^^^^^^^^^^^^^^

我不太确定编译器在这里抱怨什么类型,因为 Some None 都属于同一枚举类型.谁能解释我的代码对编译器有什么影响?

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> ,其中 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.

但是一旦您对此进行测试,将显示与借用相关的另一个错误.这是一个众所周知的问题,在

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天全站免登陆