为什么我不能在迭代HashMap时对这个元组进行解构?

时间:2015-06-17 05:49:03

标签: rust

我只是学习生锈,正在开展一项简单的/ r / dailyprogrammer任务。这是一些代码:

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);
}

我从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

似乎这两个问题都与同一个问题有关,以某种方式调用list.iter()试图给我一个(_, String, bool)而不是(String, bool)的元组。为什么会这样?

2 个答案:

答案 0 :(得分:7)

错误消息不是很易读。发生的事情是done的类型为&bool,因为您是以非拥有方式进行迭代。

  

类型不匹配解析<std::collections::hash::map::Iter<'_, collections::string::String, bool> as core::iter::Iterator>::Item == (_, bool)

基本上,您需要检查std::collections::hash::map::Iter::Item的实际类型。正如您在文档中看到的那样,它是(&'a K, &'a V)

更改

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

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

将解决您的问题。

造成这种混乱的原因是Rust的类型推断。由于您使用done作为if的参数,因此Rust知道它需要是bool类型的事实。所以它从那里倒退到done - 绑定的赋值,直到找到其他具体类型。在其他语言中,它可能是另一种方式,并且错误将发生在if条件中。

作为旁注,在您的第一次迭代for (item, _) in list.iter() {中,您只对HashMap的键感兴趣。您可以使用for item in list.keys()来获得更简洁的循环。

答案 1 :(得分:2)

  

似乎这两个都与同一个问题有关,以某种方式调用list.iter()试图给我一个元组(_,String,bool)而不是(String,bool)。为什么会这样?

你是对的,两者都与原始错误有关,但错误是错误的:

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

你得到一个(_, bool)元组,而编译器希望看到一个引用(&_, &bool)的元组。这个_很可能是编译器消息中的String(或&String),所以这不是问题。

问题是您期望,编译器需要引用,这源于iter()返回引用<< / em>迭代的集合的底层元素,简单的解决方法是更改​​匹配方式:

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

从文档中可以看出:

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

另一种方法是将done绑定到&bool,然后在使用前取消引用它:

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