简体   繁体   中英

Mismatched types error when inserting into a HashMap<&str, u64>

I am creating a simple program which reads stdin one line at a time until it reaches the end of the file, then prints the frequency of each letter (ie: character, actually technically Unicode Graphemes) in the input. The full source is on Github . I'm using rustc version 1.6.0 and cargo 0.7.0

In the program, I define a HashMap<&str, u64> to store the statistics, using the letter as the key and the number of occurrences of that letter as the value. While looping through each letter, I do the following to store the statistics:

for line in stdin.lock().lines() {
    let mut line = line.unwrap().as_str();

    // For each line, store it's character.
    for grapheme in UnicodeSegmentation::graphemes(line, true) {
        match counter.get(grapheme) {
            Some(v) => counter.insert(grapheme, v + 1),
            None => counter.insert(grapheme, 1)
        }
    }
}

(where grapheme is a reference to a string ).

I realize this might not be the best way to update the counters in the hashmap, but I believe it should technically work --- I am a total Rust n00b after all.

When I cargo build , I get:

 expected `()`,
    found `core::option::Option<u64>`
(expected (),
    found enum `core::option::Option`) [E0308]
src/main.rs:18             match counter.get(grapheme) {
src/main.rs:19                 Some(v) => counter.insert(grapheme, v + 1),
src/main.rs:20                 None => counter.insert(grapheme, 1)
src/main.rs:21             }

... from looking at the docs for E0308, and the exact error message, I understand the compiler is getting one type and expecting another; but I don't understand:

  • whether I'm seeing two mismatches or one, ie:
    • is there a mismatch between core::option::Option<u64> and core::option::Option ?
    • are there two mismatches, between () and core::option::Option<u64> and between () and core::option::Option ?
    • something else?
  • I don't understand how to tell Rust's compiler how to interpret things with the correct type (ie: what to do to fix the issue).

It's saying that the expression is returning a Option<u64> where a () (the unit value, so practically "nothing") is expected.

The expression that should return the unit value is the match . The enclosing for returns () (ie expects no value to return), so the match is expected to return nothing too. But its two branches are returning the result of the insert , an Option .

The way to tell Rust to discard the return value is to add a ; , like this;

match counter.get(grapheme) {
    Some(v) => counter.insert(grapheme, v + 1),
    None => counter.insert(grapheme, 1)
}; //add a ; here

The error message is of the form expected X, found Y (expected A, found B) . X and Y are the complete mismatching types, then, in parentheses, A and B focus on the part of the type where the first mismatch appears. This is particularly useful when the mismatch happens on types involving generics. Here's a (contrived) example:

use std::sync::{Arc, Mutex};

fn type_mismatch(x: Arc<Mutex<String>>) {}

fn main() {
    let a = Arc::new(Mutex::new(0i32));
    type_mismatch(a);
}

This gives the following error:

<anon>:7:19: 7:20 error: mismatched types:
 expected `alloc::arc::Arc<std::sync::mutex::Mutex<collections::string::String>>`,
    found `alloc::arc::Arc<std::sync::mutex::Mutex<i32>>`
(expected struct `collections::string::String`,
    found i32) [E0308]
<anon>:7     type_mismatch(a);
                           ^

Here, the type of the a variable doesn't match the type of the x parameter on type_mismatch . Notice how their types are similar, but the difference is in the type parameter for Mutex in both cases. The compiler focuses on this difference so you can spot it more easily.

As you get more familiar with the libraries you use, sometimes just reading the focused types will be enough to help you figure out what's wrong.

With your code above the match expression has type Option<u64> (because all the branches have type Option<u64> ). A for loop body must terminate with a statement so simply put a ; to make that match a statement.

match counter.get(grapheme) {
    Some(v) => counter.insert(grapheme, v + 1),
    None => counter.insert(grapheme, 1)
};

Look here for more details

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM