Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Desenlerin Kullanılabildiği Tüm Yerler

Desenler Rust’ta pek çok yerde karşımıza çıkar ve farkında olmadan onları sıkça kullanmışsınızdır. Bu bölüm, desenlerin geçerli olduğu yerleri tek tek ele alır.

match Kolları

  1. bölümde konuştuğumuz gibi, match ifadelerinin kollarında desen kullanırız. Biçimsel olarak bir match ifadesi, match anahtar sözcüğü, eşleştirilecek bir değer ve her biri bir desen ile o desene uyunca çalışacak ifadeden oluşan bir veya daha fazla koldan oluşur:
match DEGER {
    DESEN => IFADE,
    DESEN => IFADE,
    DESEN => IFADE,
}

Örneğin 6. bölümdeki Option<i32> eşleştirmesinde desenler None ve Some(i) idi. Okun solunda kalan bu kısımlar, her kolun desen kısmıdır.

match ifadelerinin önemli bir şartı, kapsamlı olmalarıdır. Yani match edilen değer için bütün olasılıklar ele alınmış olmalıdır. Bunu sağlamanın bir yolu, son kola her şeyi yakalayan bir desen koymaktır. Herhangi bir değerle eşleşen değişken adı desenleri buna örnek verilebilir.

Özel _ deseni de her şeyle eşleşir; ama hiçbir değeri bağlamaz. Bu yüzden özellikle son kolda sık kullanılır. _ desenini bölümün ilerleyen kısmında daha ayrıntılı göreceğiz.

let İfadeleri

Bu bölüme kadar desenlerin match ve if let içinde kullanıldığını açıkça konuşmuştuk; ama aslında let ifadelerinde de desen kullanıyoruz. Örneğin şu çok sıradan görünen atama bile bir desen içerir:

#![allow(unused)]
fn main() {
let x = 5;
}

Biçimsel olarak bir let ifadesi şöyledir:

let DESEN = IFADE;

Buradaki x, “buraya gelen değeri x adına bağla” diyen basit bir desendir.

Desen eşleştirme yönünü daha net görmek için 19-1 numaralı listeye bakalım. Burada let, bir demeti ayrıştırmak için kullanılıyor.

fn main() {
    let (birinci, ikinci, ucuncu) = (1, 2, 3);
}
Listing 19-1: Bir demeti ayrıştırmak ve aynı anda üç değişken oluşturmak için desen kullanmak

Burada (1, 2, 3) değeri (birinci, ikinci, ucuncu) desenine karşı eşleştiriliyor. Öğe sayısı aynı olduğu için eşleşme başarılı oluyor ve sırasıyla 1, 2, 3 değerleri bu adlara bağlanıyor.

Eğer desendeki öğe sayısı ile değerdeki öğe sayısı uyuşmazsa, türler de uyuşmaz ve derleyici hata verir. 19-2 numaralı liste bunun başarısız örneğini gösteriyor.

fn main() {
    let (birinci, ikinci) = (1, 2, 3);
}
Listing 19-2: Demetteki öğe sayısıyla uyuşmayan değişken sayısına sahip yanlış desen

Bu kodu derlemeye çalıştığınızda tür hatası alırsınız:

    Checking desenler v0.1.0 (/home/hakanbiris/github/kitap/listings/ch19-patterns-and-matching/listing-19-02)
error[E0308]: mismatched types
 --> src/main.rs:3:9
  |
3 |     let (birinci, ikinci) = (1, 2, 3);
  |         ^^^^^^^^^^^^^^^^^   --------- this expression has type `({integer}, {integer}, {integer})`
  |         |
  |         expected a tuple with 3 elements, found one with 2 elements
  |
  = note: expected tuple `({integer}, {integer}, {integer})`
             found tuple `(_, _)`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `desenler` (bin "desenler") due to 1 previous error

Bu tür durumlarda çözüm ya _ veya .. ile bazı değerleri yok saymak ya da desendeki değişken sayısını değerin yapısına uygun hale getirmektir.

Koşullu if let İfadeleri

  1. bölümde if let yapısını, tek durumu ilgilendiren kısa match biçimi olarak görmüştük. İsterseniz buna else veya else if let kolları da ekleyebilirsiniz.

19-3 numaralı liste, if let, else if, else if let ve else yapılarını birlikte kullanmanın mümkün olduğunu gösteriyor.

Filename: src/main.rs
fn main() {
    let favori_renk: Option<&str> = None;
    let sali_mi = false;
    let yas: Result<u8, _> = "34".parse();

    if let Some(renk) = favori_renk {
        println!("Arka plan olarak favori rengin olan {renk} kullaniliyor");
    } else if sali_mi {
        println!("Sali gunu yesil gunu!");
    } else if let Ok(yas) = yas {
        if yas > 30 {
            println!("Arka plan rengi olarak mor kullaniliyor");
        } else {
            println!("Arka plan rengi olarak turuncu kullaniliyor");
        }
    } else {
        println!("Arka plan rengi olarak mavi kullaniliyor");
    }
}
Listing 19-3: if let, else if, else if let ve else yapılarını karıştırmak

Bu kod, birkaç koşula göre arka plan rengini seçiyor. Kullanıcının favori rengi varsa onu kullanıyor. Favori renk yoksa ve bugün salıysa yeşil kullanıyor. Yok, yaş bilgisi dizgi olarak verildiyse ve başarıyla sayıya çevrilebildiyse bu kez yaşa göre mor veya turuncu seçiyor. Bunların hiçbiri yoksa maviye düşüyor.

Bu yapı bize match’ten daha fazla esneklik verir; çünkü tek bir değer üstünde eşleştirme yapmak zorunda değiliz.

Burada önemli bir ayrıntı da şudur: if let Ok(yas) = yas satırı, dışarıdaki yas değişkenini gölgeleyen yeni bir yas üretir. Bu yüzden yas > 30 kontrolünü o bloğun içinde yapmak zorundayız.

if let ifadelerinin dezavantajı, derleyicinin kapsamlılık denetimi yapmamasıdır. Yani son else kolunu unutursanız olası bir mantık hatası hakkında uyarı almazsınız.

Koşullu while let Döngüleri

if let ile benzer biçimde, while let de desen eşleştiği sürece döngüyü devam ettirir. 19-4 numaralı listede, bu yapıyı bir kanaldan gelen iletileri yazdırmak için kullanıyoruz.

fn main() {
    let (gonderici, alici) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        for deger in [1, 2, 3] {
            gonderici.send(deger).unwrap();
        }
    });

    while let Ok(deger) = alici.recv() {
        println!("{deger}");
    }
}
Listing 19-4: alici.recv() Ok döndürdüğü sürece değerleri yazdırmak için while let kullanmak

Bu örnek 1, 2 ve 3 yazar. recv, gönderici taraf açık olduğu sürece Ok(deger) döndürür; gönderici kapandığında ise Err gelir. while let, bu yapıyı doğal biçimde ifade etmemizi sağlar.

for Döngüleri

for döngüsünde for anahtar sözcüğünden hemen sonra gelen kısım da bir desendir. Örneğin for x in y ifadesinde x bir desendir. 19-5 numaralı liste, demeti ayrıştırmak için for içinde desen kullanımını gösteriyor.

fn main() {
    let vektor = vec!['a', 'b', 'c'];

    for (indeks, deger) in vektor.iter().enumerate() {
        println!("{deger}, {indeks}. indekste");
    }
}
Listing 19-5: Bir demeti ayrıştırmak için for döngüsünde desen kullanmak

Bu kod şu çıktıyı üretir:

a, 0. indekste
b, 1. indekste
c, 2. indekste

Burada enumerate, yineleyiciyi (indeks, deger) demetleri üretecek biçimde uyarlıyor. Desen de bu demeti iki parçaya ayırıp her birini ayrı adla kullanabilmemizi sağlıyor.

Fonksiyon Parametreleri

Fonksiyon parametreleri de desendir. 19-6 numaralı listedeki foo fonksiyonuna bakın:

fn bir_fonksiyon(deger: i32) {
    // code goes here
}

fn main() {}
Listing 19-6: Parametrelerde desen kullanan bir fonksiyon imzası

Buradaki deger de bir desendir. Tıpkı let gibi, fonksiyon parametreleri yerinde de demet ayrıştırması yapabilirsiniz. 19-7 numaralı liste bunu gösteriyor.

Filename: src/main.rs
fn koordinatlari_yazdir(&(x, y): &(i32, i32)) {
    println!("Güncel konum: ({x}, {y})");
}

fn main() {
    let nokta = (3, 5);
    koordinatlari_yazdir(&nokta);
}
Listing 19-7: Bir demeti ayrıştıran parametrelere sahip fonksiyon

Bu kod Güncel konum: (3, 5) yazar. &(3, 5) değeri &(x, y) desenine eşleşir; böylece x ile y sırasıyla 3 ve 5 olur.

Kapanış parametrelerinde de aynı şekilde desen kullanabilirsiniz; çünkü kapanışlar bu açıdan fonksiyonlara benzer.

Bu noktada desenlerin birkaç farklı yerde kullanılabildiğini gördünüz. Ancak her yerde aynı tür desenler kullanılamaz. Bazı yerlerde desenlerin çürütülemez olması gerekir; bazı yerlerde çürütülebilir desenler de kabul edilir. Şimdi buna bakalım.