Storing from within a loop a borrowed value into a container in outer space?

I set myself a small challenge to get some basic knowledge of Rust. A task:

Read a few key-value pairs from stdin and put them into a hashmap.

This, however, turned out to be more difficult than expected. Mainly because of understanding the timing of life. The following code is what I currently have after some experimentation, but the compiler just doesn't stop yelling at me.

use std::io;
use std::collections::HashMap;

fn main() {
    let mut input       = io::stdin(); 
    let mut lock        = input.lock(); 
    let mut lines_iter  = lock.lines();

    let mut map         = HashMap::new();

    for line in lines_iter {
        let text                = line.ok().unwrap();
        let kv_pair: Vec<&str>  = text.words().take(2).collect();

        map.insert(kv_pair[0], kv_pair[1]);
    }

    println!("{}", map.len());
}

      

The compiler basically says:

`text` does not live long enough

      

As far as I understand, this is due to the fact that the lifetime of the "text" is limited by the volume of the cycle. Therefore, the key-value pair that I retrieve in the loop is also bound to the boundaries of the loops. So inserting them into an external map will result in a dangling pointer since after each iteration the "text" will be destroyed. (Please tell me if I'm wrong)

The big question is, how do you solve this problem?

My intuition says:

Make an "owned copy" of the key value pair and "expand" its lifetime to the outer scope ... but I have no idea how to achieve this.

+3


source to share


2 answers


The lifetime of the "text" is limited by the volume of the cycle. Therefore, the key-value pair that I retrieve in the loop is also bound to the boundaries of the loops. So inserting them into an external map will result in a dangling pointer since after each iteration the "text" will be destroyed.

Sounds right at me.

Make an "owned copy" of the key value pair.

The property &str

has String

:



map.insert(kv_pair[0].to_string(), kv_pair[1].to_string());

      

Edit

The original code is below, but I've updated the answer above to be more idiomatic

map.insert(String::from_str(kv_pair[0]), String::from_str(kv_pair[1]));

      

+3


source


In Rust, the1.1

feature has words

been deprecated. You should now be using split_whitespace

.

Here's an alternative solution that is a little more functional and idiomatic (works with 1.3

).



use std::io::{self, BufRead};
use std::collections::HashMap;

fn main() {
    let stdin = io::stdin();

    // iterate over all lines, "change" the lines and collect into `HashMap`
    let map: HashMap<_, _> = stdin.lock().lines().filter_map(|line_res| {
        // convert `Result` to `Option` and map the `Some`-value to a pair of
        // `String`s
        line_res.ok().map(|line| {
            let kv: Vec<_> = line.split_whitespace().take(2).collect();
            (kv[0].to_owned(), kv[1].to_owned())
        })
    }).collect();

    println!("{}", map.len());
}

      

+1


source







All Articles