Hackerrank challenge. Problems with borrowing

Hi all,

I'm new to Rust language. I've decided to learn Rust while doing some exercises on Hackerrank. I'm struggling with borrowing. Please help me :pray:

/*
Task from hackerrank.com (https://www.hackerrank.com/challenges/30-dictionaries-and-maps/problem)
========================

Given  names and phone numbers, assemble a phone book that maps friends' names to their respective
phone numbers. You will then be given an unknown number of names to query your phone book for.
For each  queried, print the associated entry from your phone book on a new line in the form
name=phoneNumber; if an entry for  is not found, print Not found instead.
Note: Your phone book should be a Dictionary/Map/HashMap data structure.

Input Format
------------

The first line contains an integer, , denoting the number of entries in the phone book.
Each of the  subsequent lines describes an entry in the form of  space-separated values on a single
line. The first value is a friend's name, and the second value is an -digit phone number.

After the  lines of phone book entries, there are an unknown number of lines of queries. Each line
(query) contains a  to look up, and you must continue reading lines until there is no more input.

Note: Names consist of lowercase English alphabetic letters and are first names only.

Constrains
----------
* 1 <= n <= 1e5
* 1 <= queries <= 1e5

Output format
-------------
On a new line for each query, print Not found if the name has no corresponding entry in the phone
book; otherwise, print the full  and  in the format name=phoneNumber.

Sample Input
------------
    3
    sam 99912222
    tom 11122222
    harry 12299933
    sam
    edward
    harry

Sample Output
-------------
    sam=99912222
    Not found
    harry=12299933
*/

// Enter your code here
use std::collections::HashMap;
use std::fmt::Error;
use std::io::{self, BufRead};
use std::str::FromStr;
use std::collections::hash_map::RandomState;

fn main() -> Result<(), Error> {
    let mut phone_book: HashMap<&str, &str, RandomState> = HashMap::new();
    // let mut queries: Vec<String> = vec![String::new()];
    let stdin = io::stdin();
    let mut iterator = stdin.lock().lines();
    let mut line = iterator.next().unwrap().unwrap();
    //let mut key_value: Vec<&str>;
    let n = i32::from_str(line.trim()).unwrap();
    for _i in 0..n {
        line.clear(); // mutable borrow occurs here
        line = iterator.next().unwrap().unwrap();
        let key_value: Vec<&str> = line.trim().split_ascii_whitespace().take(2).collect();
//                                                  ---- immutable borrow occurs here
        phone_book.insert(key_value[0], key_value[1]);
    }

    // loop {
    //     stdin.lock().read_line(&mut line).unwrap();
    //     if line.trim().is_empty() {
    //         break;
    //     }
    //     queries.push(line.clone());
    // }
    //
    // for query in queries {
    //     match phone_book.get(query.as_str()) {
    //         Some(number) => println!("{} = {}", query, number),
    //         None => println!("Not found")
    //     }
    // }
    Ok(())
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `line` as mutable because it is also borrowed as immutable
  --> src/main.rs:66:9
   |
66 |         line.clear();
   |         ^^^^^^^^^^^^ mutable borrow occurs here
67 |         line = iterator.next().unwrap().unwrap();
68 |         let key_value: Vec<&str> = line.trim().split_ascii_whitespace().take(2).collect();
   |                                    ---- immutable borrow occurs here
69 |         phone_book.insert(key_value[0], key_value[1]);
   |         ---------- immutable borrow later used here

error[E0506]: cannot assign to `line` because it is borrowed
  --> src/main.rs:67:9
   |
67 |         line = iterator.next().unwrap().unwrap();
   |         ^^^^ assignment to borrowed `line` occurs here
68 |         let key_value: Vec<&str> = line.trim().split_ascii_whitespace().take(2).collect();
   |                                    ---- borrow of `line` occurs here
69 |         phone_book.insert(key_value[0], key_value[1]);
   |         ---------- borrow later used here

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0502, E0506.
For more information about an error, try `rustc --explain E0502`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

The &str type means "This is a reference to a string stored somewhere else". In this case the strings in key_value are references into the line variable, so once you reach the second iteration, you can't clear line as the phone book contains references into line, and those references would be invalidated by clearing line.

Use String to take ownership.

Alternatively you can read the entire input into memory. This would allow you to use the &str type, as the memory is not invalidated while the program runs.

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

fn main() {
    let mut input = String::new();

    io::stdin().read_to_string(&mut input).unwrap();
    
    let mut input = input.split_ascii_whitespace();
    
    // This has references into `input`, but that's ok as `input` is not
    // destroyed until the end of `main`.
    let mut phone_book: HashMap<&str, &str> = HashMap::new();
    
    let n: usize = input.next().unwrap().parse().unwrap();
    for _ in 0..n {
        let name = input.next().unwrap();
        let number = input.next().unwrap();
        phone_book.insert(name, number);
    }
    
    while let Some(name) = input.next() {
        if let Some(number) = phone_book.get(name) {
            println!("{}={}", name, number);
        } else {
            println!("Not found");
        }
    }
}

The split_ascii_whitespace is usually enough to parse this kind of problem. The newline character can usually be considered equivalently to spaces.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.