[solved]How to fix this borrowed value does not live long enough

Hi, there,

I'm learning rust according to rust-book, I have read through the book to chapter 8, and try to solve this hashmap exercise:

Using a hash map and vectors, create a text interface to allow a user to add employee names to a department in a company. For example, “Add Sally to Engineering" or “Add Amir to Sales." Then let the user retrieve a list of all people in a department or all people in the company by department, sorted alphabetically.

I just try to pratice the basic logic, read the input, get the department name, and add the employee name to a vector, the code like


use std::io;

fn main() {
    println!("Hello, borrow!");
    //department vector
    let mut engineer: Vec<&str> = vec!["a","bc","de"];

    loop {
        //read the input command
        println!("Please type your command like : Add Name to Department");
        let mut cmd = String::new();
        match io::stdin().read_line(&mut cmd){
            Ok(n) => {
                println!("{n} bytes read");
                println!("cmdadd is {cmd}");
            }
            Err(_) => continue,
        };
        let cmdadd = cmd.trim();
        //split the command string into a vector
        let cmdvec:Vec<_> = cmdadd.split_whitespace().collect();
        println!("cmdvec is : {:?}", cmdvec);
        
        let depart = cmdvec[3];
        //match the fourth element
        match depart {
            "Engineer" => {
                println!("add someone to Engineer");
                engineer.push(cmdvec[1]); //if i comment this line, the program can run
                println!("engineer is {:?}", engineer);
            },
            "Sales" => {
                println!("add someone to Sales");
            },
            _ => {
                println!("the department doesn't exist");
            },
        };

    }
}

use cargo check will give an error like

error[E0597]: `cmd` does not live long enough
  --> p26_borrow\src\main.rs:20:22
   |
12 |         let mut cmd = String::new();
   |             ------- binding `cmd` declared here
...
20 |         let cmdadd = cmd.trim();
   |                      ^^^ borrowed value does not live long enough
...
30 |                 engineer.push(cmdvec[1]); //if i comment this line, the program can run
   |                 -------- borrow later used here
...
41 |     }
   |     - `cmd` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
error: could not compile `p26_borrow` (bin "p26_borrow") due to previous error

what can i do to make this code work
thanks.

Make engineers own its data by using String instead of &str.

    let mut engineer: Vec<String> = vec!["a".into(), "bc".into(), "de".into()];
// ...
                engineer.push(cmdvec[1].into());

Rust references are for short-lived borrows, not long-lived data structures. Your cmd input buffer gets dropped at the end of the loop, so you can't store references to it in the longer-lived engineer -- that would be a dangling reference.

2 Likes

the type of the variable engineer is Vec<&'static str>, but this line:

you are pushing cmdvec[1] into the container, which has type &'a str for some lifetime 'a, and that 'a is borrowing the cmd variable (which is defined within the loop so it will not live outside the loop body).

you should use owned String type for your container, (although it's a little bit more inconvenient to create literal values) and make a new allocation every time you push a new item into it:

    //department vector
    let mut engineer: Vec<String> = vec!["a".to_owned(),"bc".to_owned(),"de".to_owned()];
    loop {
        //...
        engineer.push(cmdvec[1].to_owned());
    }

you can use to_string() or into() instead of to_owned(), all are equivalent in this case, just personal preference.

2 Likes

thank you! it works, you are my saver today, you make rust warmer...

the full code is as below ,just for reference


use std::io;

fn main() {
    println!("Hello, borrow!");
    //department vector
    let mut engineer: Vec<String> = vec!["a".into(),"bc".into(),"de".into()];

    loop {
        //read the input command
        println!("Please type your command like : Add Name to Department");
        let mut cmd = String::new();
        io::stdin().read_line(&mut cmd).expect("read command line");
        let cmdadd = cmd.trim();
        //split the command string into a vector
        let cmdvec:Vec<&str> = cmdadd.split_whitespace().collect();
        println!("cmdvec is : {:?}", cmdvec);
        
        let depart = cmdvec[3];
        //match the fourth element
        match depart {
            "Engineer" => {
                println!("add someone to Engineer");
                engineer.push(cmdvec[1].into()); 
                println!("engineer is {:?}", engineer);
            },
            "Sales" => {
                println!("add someone to Sales");
            },
            _ => {
                println!("the department doesn't exist");
            },
        };

    }
}

thank you for the clear exlaintion, it's very helpful to me to understand the conception, it's really nice to see you all here.

1 Like