An error related to a match against an incompatible type when a template matches an option
I am new to Rust and cannot get around this confusing error.
I am just trying to do a mapping on the Option
returned function get
HashMap
. If the value is returned, I want to increase it, if I don't want to add a new item to the map.
Here is the code:
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),
}
Received error:
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), | ^^^^^^^^^^^^^^^^
I'm not sure what type of compiler is complaining because both Some
, and None
are part of one and the same type of transfers. Can anyone please explain what problem the compiler has with my code?
source to share
The compiler refers to the value returned by the sleeve bodies, not the template type of each sleeve of the match.
Some(count) => *count += 1, None => map.insert(a, 0),
The expression *count += 1
evaluates to ()
(called "one" in Rust, "void" in many other languages). Expression map.insert(a, 0)
, on the other hand, returns Option<V>
, where V
is the type of the hashmap value (an integer in your case). Suddenly the error message makes sense:
= note: expected type `()` = note: found type `std::option::Option<{integer}>`
I suppose you don't even want to return anything from the block match
(remember: match
these are expressions too, so you can return something). To reverse the result of any expression, you can convert it to a statement using ;
. Let's try this:
match map.get(&a) {
Some(count) => {
*count += 1;
}
None => {
map.insert(a, 0);
}
}
The body of each sleeve is now a block (something between {
and }
), and each block contains one statement. Note that we technically don't need to change the first match as it *count += 1
already returns ()
, but that this way it is more consistent.
But once you check this, another borrowing related error will be shown. This is a well known issue and is explained in more detail here . In short: the loan checker is not smart enough to admit that your code is fine and therefore you should use the super-good entry
-API
let map = HashMap::new();
map.insert("a", 0);
let a = "a";
*map.entry(&a).or_insert(0) += 1;
source to share