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ı
- bölümde konuştuğumuz gibi,
matchifadelerinin kollarında desen kullanırız. Biçimsel olarak birmatchifadesi,matchanahtar 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);
}
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);
}
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
- bölümde
if letyapısını, tek durumu ilgilendiren kısamatchbiçimi olarak görmüştük. İsterseniz bunaelseveyaelse if letkolları 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.
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");
}
}
if let, else if, else if let ve else yapılarını karıştırmakBu 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}");
}
}
alici.recv() Ok döndürdüğü sürece değerleri yazdırmak için while let kullanmakBu ö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");
}
}
for döngüsünde desen kullanmakBu 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() {}
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.
fn koordinatlari_yazdir(&(x, y): &(i32, i32)) {
println!("Güncel konum: ({x}, {y})");
}
fn main() {
let nokta = (3, 5);
koordinatlari_yazdir(&nokta);
}
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.