重新捕获错误:借入的价值寿命不足

时间:2018-09-09 00:53:21

标签: rust

尝试使用以下代码完成https://doc.rust-lang.org/book/2018-edition/ch08-03-hash-maps.html上Rust书的“哈希图”一章:

extern crate regex;

use std::collections::HashMap;
use std::io;
use regex::Regex;

fn get_command() -> String {
    let mut input_cmd = String::new();

    io::stdin().read_line(&mut input_cmd)
        .expect("Failed to read command");
    let input_cmd = input_cmd.trim();

    input_cmd.to_string()
}

fn main() {
    println!("Add someone by typing e.g. \"Add Sally to Engineering\", list everyone in a department by typing e.g. \"List everyone in Sales\", or list everyone by typing \"List everyone\". To quit, type \"Quit\".");

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

    let add_to_dept_re = Regex::new("^Add ([A-Za-z]+) to ([A-Za-z]+)$").unwrap();
    let list_in_dept_re = Regex::new("^List everyone in ([A-Za-z]+)$").unwrap();
    let list_all_re = Regex::new("^List everyone$").unwrap();

    loop {
        let input_cmd = get_command();
        let caps = add_to_dept_re.captures(&input_cmd).unwrap();

        if add_to_dept_re.is_match(&input_cmd) {
            let dept_name = caps.get(2).unwrap().as_str();
            let employee_name = caps.get(1).unwrap().as_str();

            println!("Adding person");
            employees_by_dept.entry(&dept_name)
                .or_insert_with(Vec::new)
                .push(employee_name);
        } else if list_in_dept_re.is_match(&input_cmd) {
            println!("Listing people");
        } else if list_all_re.is_match(&input_cmd) {
            println!("Listing everyone");
        } else if input_cmd == "Quit" {
            break;
        } else {
            println!("Invalid command");
            break;
        }
    }

    println!("Bye!");
}

但是我明白了:

error[E0597]: `input_cmd` does not live long enough
  --> src/main.rs:28:45
   |
28 |         let caps = add_to_dept_re.captures(&input_cmd).unwrap();
   |                                             ^^^^^^^^^ borrowed value does not live long enough
...
48 |     }
   |     - `input_cmd` dropped here while still borrowed
...
51 | }
   | - borrowed value needs to live until here

尝试了.captures(&input_cmd.clone())和其他各种方法,但没有帮助。有什么想法吗?

1 个答案:

答案 0 :(得分:3)

锈迹记忆安全规则阻止了这种方法:您的HashMap值超过了插入的项。

请参阅下面的嵌入式注释,尤其是本书的Ownership chapter

fn main() {
    let mut employees_by_dept: HashMap<&str, Vec<&str>> = HashMap::new();

    let add_to_dept_re = Regex::new("^Add ([A-Za-z]+) to ([A-Za-z]+)$").unwrap();
    let list_in_dept_re = Regex::new("^List everyone in ([A-Za-z]+)$").unwrap();
    let list_all_re = Regex::new("^List everyone$").unwrap();

    loop {
        let input_cmd = get_command();
        let caps = add_to_dept_re.captures(&input_cmd).unwrap();// <--- input_cmd 
                                                                //is borrowed here

        // ... code for getting dept_name and employee_name references
        //     and inserting into HashMap omitted

    } // <----- The String input_cmd is dropped here (memory is freed)
      // this implies that dept_name and employee_name references 
      // points to deallocated memory

    // ... At this point you will have a live employees_by_dept HashMap
    //     that contains references to deallocated memory

    println!("Bye!");
}

改为让HashMap拥有键/项目值的所有权:

fn main() {
    println!("Add someone by typing e.g. \"Add Sally to Engineering\", list everyone in a department by typing e.g. \"List everyone in     Sales\", or list everyone by typing \"List everyone\". To quit, type \"Quit\".");

    let mut employees_by_dept: HashMap<String, Vec<String>> = HashMap::new();

    let add_to_dept_re = Regex::new("^Add ([A-Za-z]+) to ([A-Za-z]+)$").unwrap();
    let list_in_dept_re = Regex::new("^List everyone in ([A-Za-z]+)$").unwrap();
    let list_all_re = Regex::new("^List everyone$").unwrap();

    loop {
        let input_cmd = get_command();
        let caps = add_to_dept_re.captures(&input_cmd).unwrap();

        if add_to_dept_re.is_match(&input_cmd) {
            let dept_name = caps.get(2).unwrap().as_str();
            let employee_name = caps.get(1).unwrap().as_str();

            println!("Adding person");

            employees_by_dept
                .entry(dept_name.to_string())
                .or_insert_with(Vec::new)
                .push(employee_name.to_string());
        } else if list_in_dept_re.is_match(&input_cmd) {
            println!("Listing people");
        } else if list_all_re.is_match(&input_cmd) {
            println!("Listing everyone");
        } else if input_cmd == "Quit" {
            break;
        } else {
            println!("Invalid command");
            break;
        }
    }
    println!("Bye!");
}