AzLearn

تمرين إعادة البناء

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)
}
اكتب هنا