Println!() outputting my line feeds

This may seem trivial, but, hey, I'm still a learner so I'm going to ask my question anyway. Below is the code I'm currently working on:

fn main() {
    let mut depts: HashMap<String, String> = HashMap::new();
    get_dept_emp(&mut depts);

    println!("\nFrom main the map now contains:   {:?}", depts);
}

fn get_dept_emp(persons: &mut HashMap<String, String>) {
    println!("\nDepartment:   ");
    let dept = inpt_strng();
    println!("\n Employee Name:   ");
    let empl = inpt_strng();

    persons.insert(dept, empl);
}

fn inpt_strng() -> String {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
    input
}

and here is the final output after I entered "sales" and "harry" for the key and value fields:

The map now contains:   {"sales\n": "harry\n"}

It's really annoying that the \n is printing out. I'm assuming it is coming from the press of enter at the end of each input line. I find it strange that it is printing out when I print my hashmap. How do I fix this?

Thanks!

You are correct - the inpt_strng() function will give you a string that includes the newline character from pressing the enter key.

The easiest solution is to trim any trailing whitespace before returning the string:

fn inpt_strng() -> String {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
    input.trim_end().to_string()
}

Also, when you do println!("... {:?}", depts) the :? bit means it will try to print depts using the std::fmt::Debug implementation. In a hashmap, it'll write a { followed by debug-printed key-value pairs, and a trailing }. The quotes and newline characters in something like "sales\n" come from String's Debug implementation, which will try to give users a representation of the string you could paste into your code or use while debugging.

If you care about the formatting then you might want to print each item manually.

println!("\nFrom main the map now contains:");

for (key, value) in &depts {
    println!("{key}: {value}");
}

This would print something like


From main the map now contains:
sales: harry

As a quality-of-life thing, you could also update inpt_strng() to include an empty println!(). That way whenever you prompt the user for input, the cursor will be moved to the next line after they hit enter and you won't need to remember to include that leading \n to each of your print statements.

Also, we don't write code on 80-column punch cards any more so you are allowed to give inpt_strng() some vowels :wink:

2 Likes

@Michael-F-Bryan Thanks for all the good advice. That clears things up for me and I appreciate it. FYI, I first started programming using Fortran back in the day and we did use 80-column punch cards. We rubber banded them together in the right order and threw them in a wire basket next to the room where the mainframe lived. In the morning we would stop by to get a printout of our program's results, debug as necessary, visit the room where the key-punch existed, and started all over again. So, I guess I do have a thing against vowels. :grinning: It's been decades since I did any coding and it's been fun to take it up again learning Rust. :slightly_smiling_face:

6 Likes

@Michael-F-Bryan I just finished incorporating your suggestions into my code and it works well. Thanks. This is just a learning exercise from the end of Chapter 8 in a modified version of The Book (Storing Keys with Associated Values in Hash Maps - The Rust Programming Language) and has been helpful as far as learning to use hashmaps
goes. To extend the activity a little, how would I go about changing my input function so that the data could be entered in spreadsheet fashion with "Department" and "Retail" as headings to columns with Tab moving between them? This may be reaching too far for my current place in my learning, but then again, making that kind of change might actually make this little app useful.

How awesome! You already knew Fortran when it was still known as FORTRAN. You're a real programmer. You'll be happy to know that we can still write Fortran in fixed form today. So still only 80 columns (if you want to go back and reminisce the good old times) :smile:

If I understand you correctly you want to read Harry from sales from a single line that looks like this:

sales\tharry\n

If that's the case you could update your get_dep_emp function like this:

fn get_dept_emp(persons: &mut HashMap<String, String>) {
    println!("\nDepartment\tEmployee Name");
    
    let raw = inpt_strng();
    
    // splits the string at every tab, returning an iterator over each substring (excluding every tab)
    let mut split = raw.split('\t');

    // advance iterator by one element. The first element is supposed to be the department
    let dept = split.next().unwrap();

    // advance iterator by one element. The second element is supposed to be the person's name
    let empl = split.next().unwrap();

    persons.insert(dept, empl);
}