ошибка re.captures: заимствованная стоимость не живет достаточно долго - PullRequest
0 голосов
/ 09 сентября 2018

Попытка завершить главу "Карты хеша" книги Rust по адресу https://doc.rust -lang.org / book / 2018-edition / ch08-03-hash-maps.html этим кодом :

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 голосов
/ 09 сентября 2018

Правила безопасности памяти Rust предотвращают такой подход: ваше значение HashMap переживает вставленные элементы.

См. Вложенные комментарии ниже, но особенно главу Владение книги.

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!");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...