CodeBlanks Logo Icon CodeBlanks

CLI

clap ile list ve get alt komutları yaparsın.

CLI

Son adımda sorguları komut satırına bağlıyoruz. Gerçek projede clap alt komutlarıyla:

#[derive(Subcommand)]
enum Komut {
    Liste,
    Etiket { ad: String },
    Yazar { ad: String },
}

Alıştırmada aynı yapıyı dilim kalıplarıyla kuruyoruz. Her komut bir süzgece dönüşür; böylece listeleme kodu tek yerde kalır:

let suzgec: Box<dyn Fn(&Yazi) -> bool> = match args {
    ["liste"] => Box::new(|_| true),
    ["etiket", e] => Box::new(move |y| y.etiketler.iter().any(|x| x == e)),
    ["yazar", a] => Box::new(move |y| y.yazar == *a),
    [k, ..] => return Err(format!("bilinmeyen komut: {k}")),
    [] => return Err(String::from("komut gerekli")),
};

Çalıştırıcı

Süzgeç hazır olunca listeleme her komut için aynıdır. Komut işleme Result<Vec<String>, String> döndürür; main yalnızca yazdırır:

fn calistir(v: &[Yazi], args: &[&str]) -> Result<Vec<String>, String> {
    let suzgec = /* yukarıdaki match */;
    Ok(v.iter()
        .filter(|y| y.yayinda && suzgec(y))
        .map(|y| format!("{}. {}", y.id, y.konu))
        .collect())
}

Uygulama Blog CLI

veri_seti() verisi ile yukarıdaki calistir fonksiyonunu yaz. ["etiket", "web"], ["yazar", "ece"] ve ["sil"] komutlarını sırayla çalıştır; sonuç satırlarını, hatada hata: MESAJ yazdır.

Başlangıç kodu

main.rs
#[derive(Debug, Clone)]
struct Yazi {
    id: u32,
    konu: String,
    yazar: String,
    etiketler: Vec<String>,
    yayinda: bool,
}

fn veri_seti() -> Vec<Yazi> {
    let y = |id, konu: &str, yazar: &str, et: &[&str], yayinda| Yazi {
        id,
        konu: konu.to_string(),
        yazar: yazar.to_string(),
        etiketler: et.iter().map(|e| e.to_string()).collect(),
        yayinda,
    };
    vec![
        y(1, "Rust ile başlangıç", "ece", &["rust", "giriş"], true),
        y(2, "Sahiplik", "can", &["rust"], false),
        y(3, "Web sunucusu", "ece", &["rust", "web"], true),
        y(4, "Python notları", "ali", &["python"], true),
    ]
}

fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
#[derive(Debug, Clone)]
struct Yazi {
    id: u32,
    konu: String,
    yazar: String,
    etiketler: Vec<String>,
    yayinda: bool,
}

fn veri_seti() -> Vec<Yazi> {
    let y = |id, konu: &str, yazar: &str, et: &[&str], yayinda| Yazi {
        id,
        konu: konu.to_string(),
        yazar: yazar.to_string(),
        etiketler: et.iter().map(|e| e.to_string()).collect(),
        yayinda,
    };
    vec![
        y(1, "Rust ile başlangıç", "ece", &["rust", "giriş"], true),
        y(2, "Sahiplik", "can", &["rust"], false),
        y(3, "Web sunucusu", "ece", &["rust", "web"], true),
        y(4, "Python notları", "ali", &["python"], true),
    ]
}

fn calistir(v: &[Yazi], args: &[&str]) -> Result<Vec<String>, String> {
    let suzgec: Box<dyn Fn(&Yazi) -> bool> = match args {
        ["liste"] => Box::new(|_| true),
        ["etiket", e] => {
            let e = e.to_string();
            Box::new(move |y| y.etiketler.iter().any(|x| *x == e))
        }
        ["yazar", a] => {
            let a = a.to_string();
            Box::new(move |y| y.yazar == a)
        }
        [k, ..] => return Err(format!("bilinmeyen komut: {k}")),
        [] => return Err(String::from("komut gerekli")),
    };
    Ok(v.iter()
        .filter(|y| y.yayinda && suzgec(y))
        .map(|y| format!("{}. {}", y.id, y.konu))
        .collect())
}

fn main() {
    let yazilar = veri_seti();
    let komutlar: [&[&str]; 3] = [&["etiket", "web"], &["yazar", "ece"], &["sil"]];
    for k in komutlar {
        match calistir(&yazilar, k) {
            Ok(sonuclar) => {
                for s in sonuclar {
                    println!("{}", s);
                }
            }
            Err(e) => println!("hata: {}", e),
        }
    }
}

Beklenen çıktı

3. Web sunucusu
1. Rust ile başlangıç
3. Web sunucusu
hata: bilinmeyen komut: sil

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Süzgeçleri neden <code>Box&lt;dyn Fn&gt;</code> içinde tutuyoruz?

  • Her match kolu farklı türde bir closure üretir; ortak tür gerekir Doğru cevap
  • Daha hızlıdır
  • Closure'lar Box olmadan çağrılamaz
  • Gerekli değil

Açıklama: Her closure eşsiz bir türdür; bir match ifadesinin tüm kolları aynı türü döndürmelidir.

2 Ortak süzgeç türü

Soru
let suzgec: Box<dyn ____(&Yazi) -> bool> = Box::new(|_| true);
Cevap
let suzgec: Box<dyn Fn(&Yazi) -> bool> = Box::new(|_| true);

Açıklama: Birden çok kez çağrılan, yalnızca okuyan closure Fn'dir.

3 Komut ve sonuç

Kavram Anlamı
etiket web 3. Web sunucusu
yazar ali 4. Python notları
liste 1, 3, 4
sil hata: bilinmeyen komut

Orta seviye bölümündeki tüm dersler