I'm just learning rust and am working on an easy /r/dailyprogrammer task. Here's some 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'm getting 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 like both of these are related to the same issue that somehow calling list.iter()
is trying to give me a tuple of (_, String, bool)
instead of just (String, bool)
. Why is that happening?
The error message is not very readable. What is happening is that done
is of type &bool
since you are iterating in a non-owning way.
type mismatch resolving
<std::collections::hash::map::Iter<'_, collections::string::String, bool> as core::iter::Iterator>::Item == (_, bool)
:
Basically you need to check what the actual type of std::collections::hash::map::Iter::Item
is. As you can see in the docs it is (&'a K, &'a V)
.
Changing
for (item, done) in list.iter() {
to
for (item, &done) in list.iter() {
will fix your issue.
What causes this confusion, is Rust's type inference. Since you are using done
as the argument to an if
, Rust knows for a fact that it needs to be of type bool
. So it goes backwards from there to the assignment of the done
-binding until it finds some other concrete type. In other languages it would probably have been the other way around, and the error would have occurred in the if-condition.
As a side-note, in your first iteration for (item, _) in list.iter() {
you are only interested in the keys of the HashMap
. You can use for item in list.keys()
for a more concise loop.
It seems like both of these are related to the same issue that somehow calling list.iter() is trying to give me a tuple of (_, String, bool) instead of just (String, bool). Why is that happening?
You are right that both are related to the original error, but wrong about the error:
(_, bool)`: expected &-ptr,
You get a (_, bool)
tuple whereas the compiler expected to see a tuple of references (&_, &bool)
to something. This _
could well be a String
(or &String
) in the compiler message, so this not the issue.
The issue is that you are expecting a value where the compiler expects a reference, this stems from the fact that iter()
returns references to the underlying elements of the collection iterated upon and the simple fix is to change how you match:
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)
The other way around would be to bind done
to &bool
and then dereference it before use:
for (item, done) in &list {
if *done { ... } else { ... }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With