تمرين إعادة البناء
Expense Tracker
أعد كتابة متتبع مصاريف يقرأ قيماً مصنفة ويعرض المجاميع.
rust
~18 دقيقة
متوسط
أعد بناء الكود
Rebuild
هذا هو الكود. اكتبه بنفسك.
الكود المرجعي
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::io;
#[derive(Debug)]
struct Expense {
category: String,
halalas: i64,
}
fn main() -> io::Result<()> {
let path = env::args()
.nth(1)
.unwrap_or_else(|| "expenses.csv".to_string());
let data = fs::read_to_string(path).unwrap_or_else(|_| sample_expenses());
let expenses = parse_expenses(&data);
let mut totals = BTreeMap::new();
for expense in &expenses {
*totals.entry(expense.category.clone()).or_insert(0) += expense.halalas;
}
for (category, total) in totals {
println!("{category}: {}", format_money(total));
}
let grand_total: i64 = expenses.iter().map(|expense| expense.halalas).sum();
println!("Total: {}", format_money(grand_total));
Ok(())
}
fn parse_expenses(data: &str) -> Vec<Expense> {
data.lines()
.skip(1)
.filter_map(|line| {
let fields: Vec<_> = line.split(',').map(str::trim).collect();
Some(Expense {
category: fields.get(0)?.to_string(),
halalas: fields.get(2)?.parse().ok()?,
})
})
.collect()
}
fn sample_expenses() -> String {
"category,note,halalas\nFood,Lunch,4200\nTransport,Taxi,2500\nFood,Coffee,1200\n".to_string()
}
fn format_money(halalas: i64) -> String {
format!("{}.{:02} SAR", halalas / 100, halalas.abs() % 100)
}اكتب هنا