Rust'ta pattern (desen), bir değerin yapısını tarif eden ve eşleşirse parçalarını değişkenlere bağlayan sözdizimidir. Desenler yalnızca match kollarında değil; let, if let, while let, let...else, for döngüleri ve fonksiyon parametrelerinde de kullanılır. Literal'ler, değişken adları, _, |, aralıklar, struct, enum, demet ve slice parçalama, .. ile kalanı atlama, @ bağlamaları ve match guard'ları bu sözdiziminin parçalarıdır.
Bu yazı desen sözdiziminin başvuru niteliğindeki özetidir: her biçimi kısa, çalışan bir örnekle gösterir ve refutability (çürütülebilirlik) kavramını, _ ile _ad arasındaki sahiplik farkını ve 2024 edition'daki binding mode kısıtlarını açıklar. match ve if let'in kontrol akışı olarak kullanımı Rust match ve if let yazısında anlatılıyor.
Desenler nerelerde kullanılır?
Fark etmeden desen yazdığınız pek çok yer vardır. let x = 5; satırındaki x bile bir desendir: her şeyle eşleşir ve değeri bağlar. Aynı şekilde for (i, deger) in ... ifadesindeki demet ve bir fonksiyonun parametre listesi de desendir. Closure parametreleri de fonksiyon parametreleri gibi desen kabul eder.
fn konum_yaz(&(x, y): &(i32, i32)) {
println!("konum: ({x}, {y})");
}
fn main() {
let (a, b, c) = (1, 2, 3); // let ile demet parçalama
println!("{a} {b} {c}");
for (i, harf) in ['a', 'b'].iter().enumerate() {
println!("{harf} {i}. sırada");
}
konum_yaz(&(3, 5));
let ciftler = [(1, 2), (3, 4)];
let toplamlar: Vec<i32> = ciftler.iter().map(|&(x, y)| x + y).collect();
println!("{toplamlar:?}");
}
// çıktı: 1 2 3
// çıktı: a 0. sırada
// çıktı: b 1. sırada
// çıktı: konum: (3, 5)
// çıktı: [3, 7]let ile demet parçalarken desendeki eleman sayısı demetinkine eşit olmalıdır; let (x, y) = (1, 2, 3); derlenmez. konum_yaz fonksiyonunda &(x, y) deseni, &(3, 5) referansını açıp içindeki iki değeri ayrı değişkenlere bağlar.
Refutability: eşleşmeyebilecek desenler

Desenler iki türdür. Her olası değerle eşleşen desenlere irrefutable (çürütülemez), bazı değerlerde eşleşmeyebilecek desenlere refutable (çürütülebilir) denir. x çürütülemez, Some(x) ise çürütülebilirdir, çünkü değer None olabilir. Fonksiyon parametreleri, let ve for yalnızca çürütülemez desen kabul eder; değer eşleşmezse program anlamlı bir şey yapamaz. let ile çürütülebilir bir desen kullanırsanız derleyici E0005 verir:
fn main() {
let deger: Option<i32> = None;
let Some(x) = deger;
println!("{x}");
}
// error[E0005]: refutable pattern in local bindingDerleyicinin önerdiği çözüm let...else kullanmaktır; eşleşmezse çalışacak bir çıkış yolu verirsiniz. Tersi de geçerlidir: if let, while let ve let...else çürütülemez bir desenle de çalışır ama derleyici uyarır, çünkü koşullu bir yapının tek amacı başarısızlığı ele almaktır:
fn main() {
let x = 5 else {
return;
};
println!("{x}");
}
// warning: unreachable `else` clause
// çıktı: 5| Yer | Kabul ettiği desen | Not |
|---|---|---|
| let, fonksiyon parametresi, for | Yalnızca çürütülemez | Çürütülebilir desen E0005 verir |
| if let, while let, let...else | İkisi de | Çürütülemez desen uyarı verir |
| match kolları | Çürütülebilir | Son kol kalan her şeyi kapsamalı |
Literal, birden çok desen ve aralıklar
Desen olarak doğrudan literal değer yazabilirsiniz. | işleci desenlerde "veya" anlamına gelir. ..= kapsayıcı, .. ise üst sınırı dışlayan aralık desenidir; Rust Reference'a göre aralık desenleri sayı ve char tipleriyle çalışır ve boş olmamalıdır, örneğin 10..=0 geçersizdir. Tek taraflı aralıklar da tanımlıdır: 1.. 1 ve üzerini, ..0 sıfırdan küçük değerleri kapsar.
fn sinif(n: i32) -> &'static str {
match n {
..0 => "negatif",
0 => "sıfır",
1 | 2 => "bir ya da iki",
3..=9 => "tek basamaklı",
10..100 => "iki basamaklı",
_ => "büyük",
}
}
fn main() {
for n in [-4, 0, 2, 7, 42, 100] {
println!("{n}: {}", sinif(n));
}
let harf = 'ş';
let tur = match harf {
'a'..='z' => "ASCII küçük harf",
'ç' | 'ğ' | 'ı' | 'ö' | 'ş' | 'ü' => "Türkçe küçük harf",
_ => "diğer",
};
println!("{harf}: {tur}");
}
// çıktı: -4: negatif
// çıktı: 0: sıfır
// çıktı: 2: bir ya da iki
// çıktı: 7: tek basamaklı
// çıktı: 42: iki basamaklı
// çıktı: 100: büyük
// çıktı: ş: Türkçe küçük harfi32 üzerindeki bu match'te son kolu kaldırırsanız derleyici 100 ve üzerinin kapsanmadığını söyler; aralık desenleri de kapsayıcılık denetimine dahildir.
İsimli değişkenler ve gölgeleme tuzağı

match, if let ve while let yeni bir kapsam başlatır. Desende kullanılan bir değişken adı, dışarıda aynı adlı bir değişken olsa bile onunla karşılaştırma yapmaz; yeni bir değişken tanımlar ve dıştakini gölgeler. Dıştaki bir değerle karşılaştırmak için match guard gerekir:
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("50 geldi"),
Some(y) => println!("eşleşti, y = {y}"), // yeni y, dıştaki değil
_ => println!("varsayılan, x = {x:?}"),
}
match x {
Some(50) => println!("50 geldi"),
Some(n) if n == y => println!("eşleşti, n = {n}"), // guard dıştaki y'yi kullanır
_ => println!("varsayılan, x = {x:?}"),
}
println!("sonda: x = {x:?}, y = {y}");
}
// çıktı: eşleşti, y = 5
// çıktı: varsayılan, x = Some(5)
// çıktı: sonda: x = Some(5), y = 10Struct, enum ve demet parçalama
Desenler değerleri parçalarına ayırmak (destructuring) için kullanılır. Struct deseninde alan adlarından sonra iki nokta ile değişken adı yazılır; değişken adı alan adıyla aynıysa kısaltma olarak yalnızca alan adı yazılabilir. Bazı alanlar için değişken yerine literal yazarak o alanın belirli bir değere eşit olup olmadığını da test edebilirsiniz. Enum desenleri varyantın tanımlanma biçimini izler: tuple varyantlarda parantez, struct varyantlarda süslü parantez kullanılır. Desenler istenildiği kadar iç içe olabilir.
struct Nokta {
x: i32,
y: i32,
}
enum Renk {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Mesaj {
Tasi { x: i32, y: i32 },
RenkDegistir(Renk),
}
fn main() {
let p = Nokta { x: 0, y: 7 };
let Nokta { x: a, y: b } = p; // farklı adlarla
let Nokta { x, y } = p; // kısaltma
println!("{a} {b} {x} {y}");
match p {
Nokta { x, y: 0 } => println!("x ekseninde, x = {x}"),
Nokta { x: 0, y } => println!("y ekseninde, y = {y}"),
Nokta { x, y } => println!("eksenlerde değil: ({x}, {y})"),
}
let mesajlar = [
Mesaj::Tasi { x: 1, y: 2 },
Mesaj::RenkDegistir(Renk::Hsv(0, 160, 255)),
Mesaj::RenkDegistir(Renk::Rgb(255, 0, 0)),
];
for m in &mesajlar {
match m {
Mesaj::Tasi { x, y } => println!("taşı ({x}, {y})"),
Mesaj::RenkDegistir(Renk::Rgb(r, g, b)) => println!("rgb {r} {g} {b}"),
Mesaj::RenkDegistir(Renk::Hsv(h, s, v)) => println!("hsv {h} {s} {v}"),
}
}
let ((ayak, inc), Nokta { x: px, y: py }) = ((3, 10), Nokta { x: 3, y: -10 });
println!("{ayak} {inc} {px} {py}");
}
// çıktı: 0 7 0 7
// çıktı: y ekseninde, y = 7
// çıktı: taşı (1, 2)
// çıktı: hsv 0 160 255
// çıktı: rgb 255 0 0
// çıktı: 3 10 3 -10Nokta { x: 0, y: 0 } hem birinci hem ikinci kola uyardı, ama match ilk eşleşen kolda durduğu için yalnızca "x ekseninde" yazardı. Nokta'nın alanları i32 olduğu ve i32 Copy olduğu için p'yi iki kez parçalamak sorun yaratmadı; alanlardan biri String olsaydı ilk parçalama onu taşırdı.
Değerleri yok saymak: _, _ad ve ..
Bir değerin tamamını ya da bir kısmını yok saymanın dört yolu vardır. _ her şeyle eşleşir ama hiçbir şeyi bağlamaz; fonksiyon parametresinde, örneğin bir trait'in istediği imzayı karşılarken kullanılmayan parametre için işe yarar. Başka bir desenin içindeki _ yalnızca o parçayı yok sayar. Adı alt çizgiyle başlayan bir değişken kullanılmasa bile uyarı üretmez. .. ise bir struct'ın ya da demetin açıkça yazılmayan geri kalanını atlar.
struct Nokta3 {
x: i32,
y: i32,
z: i32,
}
fn main() {
let mut ayar = Some(5);
let yeni_ayar = Some(10);
match (ayar, yeni_ayar) {
(Some(_), Some(_)) => println!("var olan ayarın üzerine yazılamaz"),
_ => ayar = yeni_ayar,
}
println!("ayar: {ayar:?}");
let sayilar = (2, 4, 8, 16, 32);
let (ilk, _, ucuncu, _, besinci) = sayilar;
println!("{ilk} {ucuncu} {besinci}");
let (bas, .., son) = sayilar;
println!("{bas} {son}");
let kok = Nokta3 { x: 0, y: 1, z: 2 };
let Nokta3 { x, .. } = kok;
println!("x = {x}, y = {}, z = {}", kok.y, kok.z);
}
// çıktı: var olan ayarın üzerine yazılamaz
// çıktı: ayar: Some(5)
// çıktı: 2 8 32
// çıktı: 2 32
// çıktı: x = 0, y = 1, z = 2.. belirsiz olmamalıdır. Bir demet deseninde iki kez kullanılırsa Rust hangi elemanın hangi değişkene düşeceğini bilemez ve hata verir:
fn main() {
let sayilar = (2, 4, 8, 16, 32);
match sayilar {
(.., ikinci, ..) => println!("{ikinci}"),
}
}
// error: `..` can only be used once per tuple pattern_ ile _ad arasındaki sahiplik farkı
Bu ikisi aynı şey değildir. _ad değeri yine de bağlar; bağlanan değer Copy değilse taşınır. _ ise hiç bağlamadığı için hiçbir şeyi taşımaz. The Book bu farkı bir Option<String> ile gösterir:
fn main() {
let s = Some(String::from("Merhaba!"));
if let Some(_s) = s {
println!("metin bulundu");
}
println!("{s:?}");
}
// error[E0382]: borrow of partially moved value: `s`Some(_s) yerine Some(_) yazdığınızda String taşınmaz ve son satır Some("Merhaba!") yazdırır. Değeri kullanmayacaksanız _, kullanıp uyarıyı geçici olarak susturmak istiyorsanız _ad yazın. Taşıma kuralları için Rust ownership yazısına bakabilirsiniz.
Match guard ve öncelik
Match guard, desenin ardından gelen ek bir if koşuludur; kolun seçilmesi için desen eşleşmeli ve koşul da doğru olmalıdır. Koşul desende bağlanan değişkenleri kullanabilir. Bedeli şudur: guard içeren kollarda derleyici kapsayıcılığı koşula bakarak doğrulayamaz, bu yüzden genellikle guard'sız bir yedek kol gerekir. | ile birleştirilmiş desenlerde guard, tek bir alternatife değil desenin tamamına uygulanır:
fn main() {
let sayi = Some(4);
match sayi {
Some(x) if x % 2 == 0 => println!("{x} çift"),
Some(x) => println!("{x} tek"),
None => (),
}
let x = 4;
let y = false;
match x {
4 | 5 | 6 if y => println!("evet"), // (4 | 5 | 6) if y
_ => println!("hayır"),
}
}
// çıktı: 4 çift
// çıktı: hayırİkinci match "hayır" yazar, çünkü guard yalnızca 6'ya değil 4, 5 ve 6'nın tamamına bağlıdır ve y yanlıştır. Guard yalnızca son alternatife uygulansaydı 4 eşleşir ve "evet" yazılırdı.
@ bağlamaları
@ işleci, bir değeri bir desene karşı test ederken aynı anda bir değişkene bağlamanızı sağlar. Bir aralık deseni değeri kontrol eder ama kola değişken vermez; id @ 3..=7 ise hem aralığı test eder hem de eşleşen değeri id olarak kullanılabilir kılar:
enum Mesaj {
Selam { id: i32 },
}
fn main() {
for m in [Mesaj::Selam { id: 5 }, Mesaj::Selam { id: 11 }, Mesaj::Selam { id: 40 }] {
match m {
Mesaj::Selam { id: id @ 3..=7 } => println!("aralıkta bir id: {id}"),
Mesaj::Selam { id: 10..=12 } => println!("diğer aralıkta bir id"),
Mesaj::Selam { id } => println!("başka bir id: {id}"),
}
}
}
// çıktı: aralıkta bir id: 5
// çıktı: diğer aralıkta bir id
// çıktı: başka bir id: 40Slice desenleri
Rust Reference, diziler ve slice'lar için köşeli parantezli desenler tanımlar. .. burada sıfır veya daha fazla elemanı temsil eder ve kalan @ .. biçiminde bir değişkene bağlanabilir. Slice'ın uzunluğu derleme zamanında bilinmediği için boş, tek elemanlı ve çok elemanlı durumları ayrı kollarda ele almak, uzunluk kontrolü ve indeksleme yazmaktan çok daha güvenlidir:
fn tarif(s: &[&str]) -> String {
match s {
[] => String::from("boş"),
[tek] => format!("tek eleman: {tek}"),
[ilk, .., "z"] => format!("{ilk} ile başlıyor, z ile bitiyor"),
[bas, kalan @ ..] => format!("baş = {bas}, kalan = {kalan:?}"),
}
}
fn main() {
println!("{}", tarif(&[]));
println!("{}", tarif(&["a"]));
println!("{}", tarif(&["a", "b", "z"]));
println!("{}", tarif(&["a", "b", "c"]));
}
// çıktı: boş
// çıktı: tek eleman: a
// çıktı: a ile başlıyor, z ile bitiyor
// çıktı: baş = a, kalan = ["b", "c"]Slice'ın kendisi hakkında daha fazla bilgi için Rust slice ve &str yazısına bakabilirsiniz.
Binding mode ve 2024 edition kısıtı
Bir referansı, referans olmayan bir desenle eşleştirdiğinizde Rust referansı kendiliğinden açar ve bağlamaları ref yapar; buna varsayılan binding mode denir ve let [a, b] = &[1, 2]; yazdığınızda a ile b'nin &i32 olmasını sağlar. Edition Guide'a göre Rust 2024'te bu otomatik mod devredeyken bir bağlamaya mut, ref veya ref mut yazmak hatadır. Eski edition'larda mut yazmak modu sessizce "move"a çeviriyor ve tipi değiştiriyordu; bu şaşırtıcı davranış 2024'te kaldırıldı:
fn main() {
let dizi = &[1u8, 2];
let [mut a, b] = dizi;
a += 1;
println!("{a} {b}");
}
// error: cannot mutably bind by value within an implicitly-borrowing patternÇözüm, deseni tamamen açık yazmaktır: dıştaki referansı & deseniyle siz açarsanız varsayılan mod "move" olarak kalır ve mut yazmak serbesttir.
fn main() {
let dizi = &[1u8, 2];
let &[mut a, b] = dizi; // referansı desende açıkça açıyoruz
a += 1;
println!("{a} {b}");
}
// çıktı: 2 2Desen biçimleri özet tablosu
Aşağıdaki tablo bu yazıda gördüğümüz desen biçimlerini tek yerde toplar. Hepsi birbiriyle iç içe kullanılabilir; örneğin bir enum deseni içinde aralık, aralığın üzerinde @ bağlaması ve kolun sonunda bir guard aynı anda bulunabilir.
| Biçim | Örnek | Ne yapar |
|---|---|---|
| Literal | 1, "evet", true | Değere eşitse eşleşir |
| Değişken | x | Her şeyle eşleşir ve değeri bağlar |
| Joker | _ | Her şeyle eşleşir, bağlamaz |
| Veya | 1 | 2 | Alternatiflerden biri eşleşirse eşleşir |
| Aralık | 3..=9, 'a'..='z', ..0 | Sayı veya char aralığında eşleşir |
| Struct | Nokta { x, y: 0 } | Alanları parçalar, literal alanları test eder |
| Enum | Some(x), Mesaj::Tasi { x, y } | Varyantı ve içindeki veriyi eşleştirir |
| Demet | (a, .., z) | Elemanları sırayla parçalar |
| Slice | [ilk, kalan @ ..] | Uzunluğa göre eşleşir ve parçalar |
| Referans | &(x, y) | Referansı açıp içini eşleştirir |
| Bağlama | id @ 3..=7 | Test eder ve değeri bağlar |
| Guard | Some(x) if x > 0 | Desenden sonra ek koşul (yalnızca match) |
Desenleri okurken soldan sağa ve dıştan içe ilerleyin: önce değerin tipi ve varyantı, sonra içteki alanlar, en son da guard koşulu kontrol edilir. Bir kol eşleşmediğinde Rust bir sonraki kola geçer; kollardan hiçbirinin eşleşmeme ihtimali kalmaması gerektiği için son kolda genellikle _ ya da bir değişken adı bulunur.
Sık yapılan hatalar

- Desende dış değişkenle karşılaştırma yaptığını sanmak:
Some(y)yeni birytanımlar; karşılaştırma için guard yazın. _adile değeri farkında olmadan taşımak: Değeri kullanmayacaksanız yalnızca_yazın.- Guard'ın kapsayıcılığı sağladığını sanmak: Derleyici guard koşullarını analiz etmez; guard'sız bir yedek kol ekleyin.
|ile guard önceliğini karıştırmak:4 | 5 | 6 if yifadesinde koşul üç alternatifin hepsine uygulanır.letile çürütülebilir desen kullanmak: E0005 alırsınız;let...else,if letveyamatchkullanın.- 2024 edition'da örtük referans içinde
mutyazmak: Deseni&[mut a, b]gibi açık yazın ya da önce değeri kopyalayın.
Sık Sorulan Sorular
Desenlerde değişken ile sabit nasıl ayırt edilir?
Rust Reference'a göre path desenleri sabitlere, enum varyantlarına ve alansız struct'lara başvurabilir ve bu durumda değerle karşılaştırma yapılır. Kapsamda const SINIR: i32 = 5; varken SINIR => ... kolu yalnızca 5 ile eşleşir; bunu Rust 1.99.1 ile denedik. Böyle bir öğeye karşılık gelmeyen tek bir ad ise her değerle eşleşir ve yeni bir değişken bağlar.
match guard ile let zinciri arasındaki fark nedir?
Guard yalnızca match kollarında kullanılır. 2024 edition'da if ve while koşullarında let ifadelerini && ile zincirleyerek benzer bir etki elde edebilirsiniz; ayrıntı için Rust 2024 edition yazısına bakın.
Aralık desenlerinde hangi tipler kullanılabilir?
Reference'a göre aralık sınırları karakter, bayt, tamsayı veya kayan noktalı sayı literal'i ya da bu tiplerde bir sabite giden yol olabilir; kayan noktalı sınırlar NaN olamaz. Aralığın en az bir değeri kapsaması gerekir.
Bir değeri hem parçalayıp hem bütün olarak kullanabilir miyim?
Evet, @ ile: butun @ [.., son] deseni slice'ın tamamını butun'a, son elemanı da son'a bağlar. Rust Reference'taki rest pattern örneği bunu gösterir.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Rust öğrenme rehberi · match ve if let · Enum ve Option · Slice · Struct ve metotlar · Ownership · Rust 2024 edition · Rust nedir?