Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about Rust HashMap and String borrowing

This program accepts an integer N, followed by N lines containing two strings separated by a space. I want to put those lines into a HashMap using the first string as the key and the second string as the value:

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

fn main() {
    let mut input = String::new();
    io::stdin().read_line(&mut input)
        .expect("unable to read line");
    let desc_num: u32 = match input.trim().parse() {
        Ok(num) => num,
        Err(_) => panic!("unable to parse")
    };

    let mut map = HashMap::<&str, &str>::new();
    for _ in 0..desc_num {
        input.clear();
        io::stdin().read_line(&mut input)
            .expect("unable to read line");
        let data = input.split_whitespace().collect::<Vec<&str>>();
        println!("{:?}", data);
        // map.insert(data[0], data[1]);
    }
}

The program works as intended:

3
a 1
["a", "1"]
b 2
["b", "2"]
c 3
["c", "3"]

When I try to put those parsed strings into a HashMap and uncomment map.insert(data[0], data[1]);, the compilation fails with this error:

error: cannot borrow `input` as mutable because it is also borrowed as immutable [E0502]
        input.clear();
        ^~~~~
note: previous borrow of `input` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `input` until the borrow ends
        let data = input.split_whitespace().collect::<Vec<&str>>();
                   ^~~~~
note: previous borrow ends here
fn main() {
...
}
^

I don't understand why this error would come up, since I think the map.insert() expression doesn't borrow the string input at all.

like image 431
B. Wang Avatar asked Oct 11 '25 22:10

B. Wang


1 Answers

split_whitespace() doesn't give you two new Strings containing (copies of) the non-whitespace parts of the input. Instead you get two references into the memory managed by input, of type &str. So when you then try to clear input and read the next line of input into it, you try overwriting memory that's still being used by the hash map.

Why does split_whitespace (and many other string methods, I should add) complicate matters by returning &str? Because it's often enough, and in those cases it avoid unnecessary copies. In this specific case however, it's probably best to explicitly copy the relevant parts of the string:

map.insert(data[0].clone(), data[1].clone());

Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!