Rust:借来的价值活得不够长

7dl7o3gd  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(143)

我是Rust的新手,正在为leetcode问题研究Rust解决方案,“49。组Anagrams”,并遇到了一个问题,一个借来的价值没有生存足够长的错误。
还有一些其他相关的SOF线程,但我有困难理解的内容。
错误:

error[E0597]: `key` does not live long enough
  --> src/main.rs:14:18
   |
9  |     let key: String = sort_letters(&w);
   |         --- binding `key` declared here
10 |
11 |     if map.contains_key(&key as &str) {
   |        --- borrow later used here
...
14 |       map.insert(&key as &str, val);
   |                  ^^^^ borrowed value does not live long enough
...
20 |   }
   |   - `key` dropped here while still borrowed
fn main() {
    use std::any::type_name;
    use std::collections::HashMap;

    let words: Vec<&str> = vec!["eat", "tea", "tan", "ate", "nat", "bat"];
    let mut map: HashMap<&str, Vec<&str>> = HashMap::new();

    for w in words {
        let key: String = sort_letters(&w);

        if map.contains_key(&key as &str) {
            let mut val: Vec<&str> = map.get(&key as &str).unwrap().to_vec();
            val.push(w);
            map.insert(&key as &str, val);
        } else {
            let mut val = Vec::new();
            val.push(w);
            map.insert(&key as &str, val);
        }
    }
}

fn sort_letters(w: &str) -> String {
    let mut chars: Vec<char> = w.chars().collect();
    chars.sort();
    chars.into_iter().collect::<String>()
}

我试着克隆这个键来给&键给予新的所有权,但这给了我同样的错误。

ct3nt3jp

ct3nt3jp1#

let mut map: HashMap<&str, Vec<&str>> = HashMap::new();

好的,我们将有一个Map,但这个Map不会拥有它的键:键将是对由其他东西拥有的字符串的引用。

for w in words {
        let key: String = sort_letters(&w);
...
            map.insert(&key as &str, val);
...
    }

现在我们循环一些单词,在每次迭代中,我们创建一个包含单词字母的字符串。(顺便说一句:不需要用类型String注解key,rust足够聪明,可以解决这个问题)。
该字符串值由变量key拥有,这意味着当它超出范围时(在循环迭代结束时),该字符串将被删除。
然后几行之后,我们向Map添加一个条目,键是对同一个字符串值的引用(它实际上发生在if语句的两个分支中,为了简单起见,我只显示一个)。
然后是循环的结束。变量key超出作用域,值被删除-但Map仍然引用它!
解决方案是让map拥有key,就像这样:

let mut map: HashMap<String, Vec<&str>> = HashMap::new();

然后循环看起来像这样:

for w in words {
        let key: String = sort_letters(&w);

        if map.contains_key(&key) {
            let mut val: Vec<&str> = map.get(&key).unwrap().to_vec();
            val.push(w);
            map.insert(key, val);
        } else {
            let mut val = Vec::new();
            val.push(w);
            map.insert(key, val);
        }
    }

这将工作,但它是非常低效的。

let mut val: Vec<&str> = map.get(&key).unwrap().to_vec();

to_vec在map中创建Vec的副本,然后我们将新单词添加到Vec的末尾,并将新的Vec放回map中。我们不断地创建新的Vec s,并将旧值复制到新值。
有一个更简单更好的方法。HashMap有另一个方法entry,它允许您非常干净地实现“查找或插入条目”模式。使用entry,你的循环看起来像这样:

for w in words {
        let key: String = sort_letters(&w);

        map.entry(key)
           .or_insert_with(Vec::new)
           .push(w);
    }

entry方法返回一个Entry结构体,如果条目不存在,该结构体有各种方法来填充条目。它还为我们提供了对新条目或现有条目的可变访问,我们可以直接将单词推到上面。

相关问题