Why can't I destroy this tuple when navigating through a HashMap?

I just study rust and work on the easy / r / dailyprogrammer task. Here is the code:

type ToDoList = HashMap<String, bool>; fn print(list: &ToDoList) { let mut max_len: usize = 0; for (item, _) in list.iter() { max_len = max(max_len, item.len()); } let end = format!("+---{}-+", iter::repeat("-").take(max_len).collect::<String>()); println!("{}", end); for (item, done) in list.iter() { let line = format!("| {0} {1}{2} |", if done {"β˜‘"} else {"☐"}, item, iter::repeat("-") .take(max_len - item.len()) .collect::<String>() ); println!("{:?}", (item, done)); } println!("{}", end); } 

I get this error from rustc:

 error: type mismatch resolving `<std::collections::hash::map::Iter<'_, collections::string::String, bool> as core::iter::Iterator>::Item == (_, bool)`: expected &-ptr, found bool [E0271] todolist.rs:19 for (item, done) in list.iter() { todolist.rs:20 let line = format!("| {0} {1}{2} |", todolist.rs:21 if done {"β˜‘"} else {"☐"}, todolist.rs:22 item, todolist.rs:23 iter::repeat("-") todolist.rs:24 .take(max_len - item.len()) ... todolist.rs:24:21: 24:31 error: the type of this value must be known in this context todolist.rs:24 .take(max_len - item.len()) ^~~~~~~~~~ note: in expansion of format_args! <std macros>:2:26: 2:57 note: expansion site <std macros>:1:1: 2:61 note: in expansion of format! todolist.rs:20:14: 26:4 note: expansion site error: aborting due to 2 previous errors 

It seems that both of them are related to the same problem, which somehow causes list.iter() , trying to give me a tuple (_, String, bool) instead of just (String, bool) . Why is this happening?

+5
source share
2 answers

The error message is not very readable. What happens is that done is of type &bool , since you iterate out of your own discretion.

resolve mismatch of type <std::collections::hash::map::Iter<'_, collections::string::String, bool> as core::iter::Iterator>::Item == (_, bool) :

Basically you need to check what the actual type std::collections::hash::map::Iter::Item . As you can see in the docs, this is (&'a K, &'a V) .

The change

 for (item, done) in list.iter() { 

to

 for (item, &done) in list.iter() { 

will fix your problem.

What causes this confusion is Rust type inference. Since you use done as an argument to if , Rust knows that it must be of type bool . Thus, it moves back from the assignment to the done binding until it finds another specific type. In other languages, this would probably be the other way around, and an error would occur in the if condition.


As a side note, in your first iteration for (item, _) in list.iter() { you are only interested in the keys to the HashMap . You can use for item in list.keys() for a more concise loop.

+7
source

It seems that both of them are related to the same problem, that somehow the call to list.iter () is trying to give me a tuple (_, String, bool), and not just (String, bool). Why is this happening?

You are right that both of them are related to the original error, but mistakenly refer to the error:

 (_, bool)`: expected &-ptr, 

You get a tuple (_, bool) , while the compiler should see something in the link court (&_, &bool) . This _ could be String (or &String ) in the compiler message, so this is not a problem.

The problem is that you are expecting a value when the compiler is expecting a link, this is because iter() returns links to the basic elements of the collection, iteration, and a simple fix is ​​to change how you agree:

 for (item, &done) in &list { } 

As can be seen in the docs:

 impl<'a, K, V> Iterator for Iter<'a, K, V> type Item = (&'a K, &'a V) 

Another way would be to bind done to &bool and then dereference it before use:

 for (item, done) in &list { if *done { ... } else { ... } } 
+2
source

All Articles