首页 > 解决方案 > 使用 HashMap 解决借用问题(2020 年代码出现的剧透)

问题描述

第一次发布海报,对 Rust 非常陌生。在过去的几个月里,我一直在慢慢地玩 Rust,而我最近才努力学习这门语言。为了帮助我解决这个问题,我计划解决今年Rust代码出现的所有问题。目前我被困在第四天。如果你想在这里阅读它是链接。显然,我可能会为你们中的一些人破坏这个问题,所以请注意!无论如何要解决问题!

对于这个问题,我决定使用 HashMap 来解决第一部分。我来自 Java 和 Python,所以我认为 Rust 的 HashMap 的工作方式类似于 Java 和 Python 的字典。我意识到这可能不是最好的解决方案,但我还是想尝试一下以了解 HashMaps。这是我想出的代码。我试图注释代码以便更容易理解。

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::collections::HashMap;

fn check_passport_valid(passport: HashMap<&str, &str>) -> bool {
    return true;
}

fn main() {
    // set up a bufReader to read the data
    let data = "data/data.txt";
    let file = File::open(data).unwrap();
    let reader = BufReader::new(file);

    // init a mutable HashMap 
    let mut passport: HashMap<&str, &str> = HashMap::new();
    let mut count = 0;

    // read the data in line by line
    for line in reader.lines() {
        // not sure if i should &line.unwrap() or do this
        // seems to work the same in both situations
        let s = line.unwrap();

        // if line is blank check password and init new HashMap
        if "" == s {
            if check_passport_valid(passport) { count += 1; }
            passport = HashMap::new();
        } 
        
        // else put values into HashMap
        else {
            // first split into items
            let items: Vec<&str> = s.split(' ').collect();
            for item in items {
                // split into key/value pair
                let pair: Vec<&str> = item.split(':').collect();
                passport.insert(pair[0], pair[1]);
            }
        }
    }

    println!("{}", count);
}

如您所见,它没有完成,但是我收到以下错误:

error[E0597]: `s` does not live long enough
  --> src/main.rs:34:36
   |
27 |             if check_passport_valid(passport) { count += 1; }
   |                                     -------- borrow later used here
...
34 |             let items: Vec<&str> = s.split(' ').collect();
   |                                    ^ borrowed value does not live long enough
...
41 |     }
   |     - `s` dropped here while still borrowed

我尝试过借用不同的值,但我似乎无法让它发挥作用。任何帮助将不胜感激!

标签: rust

解决方案


你得到的错误是你得到的值s.split(' ')是变量的切片lines,这基本上意味着它们引用了lines变量。在循环结束时,该lines变量被删除并由下一行替换,这会使对其的所有引用无效。最简单的方法是将 转换&strString(拥有的类型) with .to_owned(),因此它将数据复制到不再依赖于lines变量的静态内存位置:

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::collections::HashMap;

// this is now HashMap<String, String> instead of HashMap<&str, &str>
fn check_passport_valid(passport: HashMap<String, String>) -> bool {
    return true;
}

fn main() {
    let data = "data/data.txt";
    let file = File::open(data).unwrap();
    let reader = BufReader::new(file);

    // this is now HashMap<String, String> instead of HashMap<&str, &str>
    let mut passport: HashMap<String, String> = HashMap::new();
    let mut count = 0;

    for line in reader.lines() {
        let s = line.unwrap();

        if "" == s {
            if check_passport_valid(passport) { count += 1; }
            passport = HashMap::new();
        } 
        
        else {
            let items: Vec<&str> = s.split(' ').collect();
            for item in items {
                let pair: Vec<&str> = item.split(':').collect();
                // call to_owned on both elements
                passport.insert(pair[0].to_owned(), pair[1].to_owned());
            }
        }
    }

    println!("{}", count);
}

在此处阅读有关strvs的更多信息。String


推荐阅读