employee db
background
The final section of the eighth chapter of the rust book ends with some suggested exercises. The last of which is to write a program that:
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.
solution
Originally, the idea was to wrap an Instruction enum in a Command struct so that
we could have a classmethod from_string that could parse user input directly; I
was under the impression that an enum couldn’t have a constructor method.
Other than that, I dropped the “to” in the Add commands for simplicity. But,
looking back, I didn’t do much to enforce it. If a command started with Add we
just take the first 3 words in the input.
use std::collections::HashMap;
use std::io;
#[derive(Debug)]
enum Instruction {
Add { name: String, department: String },
View { department: String },
Unknown
}
#[derive(Debug)]
struct Command {
instruction: Instruction
}
impl Command {
fn from_string(input: String) -> Self {
let words: Vec<&str> = input.split(" ").collect();
if words[0] == "Add" {
return Self {
instruction: Instruction::Add {
name: words[1].to_string(),
department: words[2].to_string()
}
}
} else if words[0] == "View" {
return Self {
instruction: Instruction::View {
department: words[1].to_string()
}
}
} else {
return Self { instruction: Instruction::Unknown }
}
}
}
fn main() {
let mut db = HashMap::new();
println!("Welcome to the company employee management database!");
loop {
println!("Your command: ");
let mut command = String::new();
io::stdin()
.read_line(&mut command)
.expect("Failed to read line");
let command = Command::from_string(command.trim().to_string());
match command.instruction {
Instruction::Add{name, department} => {
let department_names = db.entry(department).or_insert(Vec::new());
department_names.push(name);
}
Instruction::View{department} => {
if department == "All" {
for (dept, names) in &mut db {
println!("{} department includes:", dept);
names.sort();
for name in names {
println!("{}", name);
}
}
} else {
println!("{} department includes:", department);
let names = db.entry(department).or_insert(Vec::new());
names.sort();
for name in names {
println!("{}", name);
}
}
}
Instruction::Unknown => println!("Unknown command...")
}
}
Redundant Command struct, repetitive vector printing that could be extracted
into a function, and lack of proper exception handling and out of index panics
aside, it’s not the worst for 8 chapters in.
We catch unknown commands at least…