Çürütülebilirlik (Refutability): Bir Desenin Eşleşmeme İhtimali
Desenler iki biçimde karşımıza çıkar: çürütülebilir ve çürütülemez. Aktarılan her olası değerle eşleşecek olan desenler çürütülemez (irrefutable) desenlerdir. Buna bir örnek, let x = 5; deyimindeki x desenidir; çünkü x her şeyle eşleşir ve dolayısıyla eşleşmemesi mümkün değildir. Bazı olası değerler için eşleşmesi başarısız olabilen desenler ise çürütülebilir (refutable) desenlerdir. Buna örnek olarak if let Some(x) = bir_deger ifadesindeki Some(x) verilebilir; çünkü bir_deger değişkenindeki değer Some yerine None olursa Some(x) deseni eşleşmeyecektir.
Fonksiyon parametreleri, let deyimleri ve for döngüleri yalnızca çürütülemez desenleri kabul edebilir; çünkü değerler eşleşmediğinde programın yapabileceği anlamlı hiçbir şey yoktur. if let ve while let ifadeleri ile let...else deyimi ise hem çürütülebilir hem de çürütülemez desenleri kabul eder; ancak derleyici çürütülemez desenlere karşı uyarı verir. Çünkü bu yapılar tanım gereği olası başarısızlık durumlarını ele almak için tasarlanmıştır: Bir koşul yapısının işlevselliği, başarı ya da başarısızlık durumuna göre farklı davranabilme yeteneğinde yatar.
Genel olarak çürütülebilir ve çürütülemez desenler arasındaki ayrım konusunda endişelenmenize gerek yoktur; ancak bir hata mesajında gördüğünüzde ne yapacağınızı bilmek için çürütülebilirlik kavramına aşina olmanız gerekir. Böyle durumlarda, kodun amaçlanan davranışına bağlı olarak ya deseni ya da deseni birlikte kullandığınız dil yapısını değiştirmeniz gerekecektir.
Şimdi Rust’ın çürütülemez bir desen zorunlu kıldığı yerde çürütülebilir bir desen kullanmaya çalıştığımızda — ve bunun tersi durumda — ne olduğuna bir örnekle bakalım. Liste 19-8 bir let deyimi göstermektedir, ancak desen olarak çürütülebilir bir desen olan Some(x) belirtilmiştir. Tahmin edebileceğiniz gibi bu kod derlenmeyecektir.
fn main() {
let bir_secenek_degeri: Option<i32> = None;
let Some(x) = bir_secenek_degeri;
}
let ile çürütülebilir bir desen kullanmaya çalışmakEğer bir_secenek_degeri bir None değeri olsaydı Some(x) deseniyle eşleşemezdi; bu da desenin çürütülebilir olduğu anlamına gelir. Oysa let deyimi yalnızca çürütülemez bir deseni kabul edebilir; çünkü bir None değeriyle kodun yapabileceği geçerli hiçbir işlem yoktur. Derleme zamanında Rust derleyicisi, çürütülemez bir desenin gerektiği yerde çürütülebilir bir desen kullanmaya çalıştığımızı belirterek hata verir:
$ cargo run
Compiling desenler v0.1.0 (file:///projects/desenler)
error[E0005]: refutable pattern in local binding
--> src/main.rs:3:9
|
3 | let Some(x) = bir_secenek_degeri;
| ^^^^^^^ pattern `None` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
= note: the matched value is of type `Option<i32>`
help: you might want to use `let...else` to handle the variant that isn't matched
|
3 | let Some(x) = bir_secenek_degeri else { todo!() };
| ++++++++++++++++
For more information about this error, try `rustc --explain E0005`.
error: could not compile `desenler` (bin "desenler") due to 1 previous error
Some(x) deseniyle her geçerli değeri kapsamadığımız (ve zaten kapsayamayacağımız!) için Rust haklı olarak bir derleyici hatası üretir.
Çürütülemez bir desenin gerektiği yerde elimizde çürütülebilir bir desen varsa, bunu deseni kullanan kodu değiştirerek düzeltebiliriz: let kullanmak yerine let...else kullanabiliriz. Böylece desen eşleşmezse, süslü parantezler içindeki kod bu durumu ele alır. Liste 19-9, Liste 19-8’deki kodun nasıl düzeltileceğini göstermektedir.
fn main() {
let bir_secenek_degeri: Option<i32> = None;
let Some(x) = bir_secenek_degeri else {
return;
};
}
let yerine let...else ve bir blok kullanmakNot: let...else deyimindeki else bloğu ıraksayan (diverging, dönüş
türü ! — never type olan) bir blok olmak zorundadır; yani return,
break, continue veya panic! gibi kontrol akışını mevcut kapsamdan
çıkaran bir ifadeyle sonlanmalıdır. Normal akışın else bloğundan çıkıp alt
satırlara devam etmesine izin verilmez; böylece let...else satırından sonra
gelen dış kapsamda x değişkeninin her zaman ilklenmiş olması derleme
zamanında garanti edilir.
Koda bir çıkış yolu verdik! Bu kod tamamen geçerlidir; ancak bu aynı zamanda, bir uyarı almadan çürütülemez bir desen kullanamayacağımız anlamına gelir. Liste 19-10’da gösterildiği gibi let...else yapısına x gibi her zaman eşleşecek bir desen verirsek derleyici bir uyarı üretecektir.
fn main() {
let x = 5 else {
return;
};
}
let...else ile çürütülemez bir desen kullanmaya çalışmakRust derleyicisi, else bloğuna hiçbir zaman ulaşılamayacağı için let...else yapısını çürütülemez bir desenle kullanmanın mantıklı olmadığı konusunda uyarır:
$ cargo run
Compiling desenler v0.1.0 (file:///projects/desenler)
warning: unreachable `else` clause
--> src/main.rs:2:15
|
2 | let x = 5 else {
| --------- ^^^^
| |
| assigning to binding pattern will always succeed
|
= note: this pattern always matches, so the else clause is unreachable
= note: `#[warn(irrefutable_let_patterns)]` on by default
warning: `desenler` (bin "desenler") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/desenler`
Bu nedenle match kolları — geriye kalan tüm değerlerle çürütülemez bir desen kullanarak eşleşmesi gereken son kol dışında — çürütülebilir desenler kullanmak zorundadır. Çürütülemez bir desenin ardından başka kollar gelirse o kollara hiçbir zaman ulaşılamaz; derleyici bu durumda unreachable_pattern uyarısı verir. Rust, tek kollu bir match ifadesinde çürütülemez bir desen kullanmamıza izin verir; ancak bu sözdizimi pek kullanışlı değildir ve daha basit bir let deyimiyle değiştirilebilir.
Artık desenlerin nerelerde kullanılacağını ve çürütülebilir ile çürütülemez desenler arasındaki farkı bildiğinize göre, desen oluşturmak için kullanabileceğimiz tüm sözdizimlerini ele alalım.