"borrowed value does not live long enough"似乎责怪了错误的事情



我正在计算一个单词在《麦克白:》中出现的次数

use std::io::{BufRead, BufReader};
use std::fs::File;
use std::collections::HashMap;
fn main() {
    let f = File::open("macbeth.txt").unwrap();
    let reader = BufReader::new(f);
    let mut counts = HashMap::new();
    for l in reader.lines() {
        for w in l.unwrap().split_whitespace() {
            let count = counts.entry(w).or_insert(0);
            *count += 1;
        }
    }
    println!("{:?}", counts);
}

Rust对此发表评论,称:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:14:9
   |
11 |         for w in l.unwrap().split_whitespace() {
   |                  ---------- temporary value created here
...
14 |         }
   |         ^ temporary value dropped here while still borrowed
...
18 | }
   | - temporary value needs to live until here
   |
   = note: consider using a `let` binding to increase its lifetime

实际的问题是w是一个引用,所以将其更改为w.to_string()就解决了这个问题。我不明白为什么Rust编译器将责任归咎于l,而问题则是w。我应该如何推断w是这里的问题?

将责任归咎于l

事实并非如此。再次查看错误消息:

     for w in l.unwrap().split_whitespace() {
              ---------- temporary value created here

错误标记指向unwrapl的调用。

当问题是w

事实并非如此。CCD_ 10属于CCD_。当您调用unwrap时,会得到一个String,然后split_whitespace返回对该字符串的引用。这些引用的寿命仅与字符串一样长,但您的代码试图将它们放入一个比字符串寿命更长的哈希图中。问题是l.unwrap()的寿命不够长,而w只是指寿命不够长的东西。

从概念上讲,这与此代码的问题相同:

use std::collections::HashMap;
fn main() {
    let mut counts = HashMap::new();
    {
        let s = String::from("hello world");
        counts.insert(&s, 0);
    }
    println!("{:?}", counts);
}

它还指向s,并表示它的寿命不够长(因为它没有)。

正确的解决方案是将每个单词转换为一个拥有的String,然后HashMap可以保存:

for l in reader.lines() {
    for w in l.unwrap().split_whitespace() {
        counts.entry(w.to_string()).or_insert(0) += 1;
    }
}

这里的错误既对也错。l受到指责,因为w的寿命仅与l(和l.unwrap())一样长,而l的寿命不足以将其放在更高范围的哈希图中。

在实践中,您只需要看看编译器抱怨的变量的生存期依赖于哪些其他变量。

但Rust最近也在改进错误报告,所以我认为这是一个潜在的错误。

相关内容

最新更新