Bölüm 3 — Konu 12: `switch` / `switch expression` (Modern Dart)
Dizi · 12/64 Dart Türkçe Tutorial
- Bölüm 1 — Konu 1: Dart Nedir, Nerede Kullanılır, Neden Flutter Bu Dili Seçti
- Bölüm 1 — Konu 2: Ortam Kurulumu (Dart SDK, DartPad, Terminal ile Çalıştırma)
- Bölüm 1 — Konu 3: İlk Program (`main()`, `print()`, Dosya Yapısı)
- Bölüm 1 — Konu 4: Yorum Satırları, Temel Sözdizimi Kuralları
- Bölüm 2 — Konu 5: Değişken Tanımlama — `var`, `final`, `const` Farkı
- Bölüm 2 — Konu 6: Temel Tipler — `int`, `double`, `String`, `bool`
- Bölüm 2 — Konu 7: Tip Çıkarımı (Type Inference) ve Açık Tip Belirtme
- Bölüm 2 — Konu 8: `dynamic` ve `Object` — Ne Zaman Kullanılır, Ne Zaman Kaçınılır
- Bölüm 2 — Konu 9: Null Safety Temelleri (`?`, `!`, `late`'e Giriş)
- Bölüm 3 — Konu 10: Aritmetik, Atama, Karşılaştırma, Mantıksal Operatörler
- Bölüm 3 — Konu 11: `if / else if / else`
- Bölüm 3 — Konu 12: `switch` / `switch expression` (Modern Dart)
- Bölüm 3 — Konu 13: Ternary Operatör, `??`, `??=`, `?.`
- Bölüm 3 — Konu 14: `for`, `while`, `do-while` Döngüleri
- Bölüm 4 — Konu 16: `List` — Oluşturma, Erişim, Temel Metodlar
- Bölüm 4 — Konu 17: `Set` — Benzersiz Eleman Mantığı
- Bölüm 4 — Konu 18: `Map` — Key-Value Yapılar
- Bölüm 4 — Konu 19: Koleksiyon Üzerinde `for-in`, `forEach`
- Bölüm 4 — Konu 20: Spread Operatörü (`...`, `...?`) ve Collection If/For
- Bölüm 5 — Konu 21: Fonksiyon Tanımlama, Parametreler (Positional, Named, Optional)
- Bölüm 5 — Konu 22: Varsayılan Parametre Değerleri (Derinlemesine)
- Bölüm 5 — Konu 23: Arrow Function (`=>`) Sözdizimi
- Bölüm 5 — Konu 24: Fonksiyonlar Birinci Sınıf Vatandaş — Değişkene Atama, Parametre Olarak Geçme
- Bölüm 5 — Konu 25: Anonim Fonksiyonlar ve Closure Kavramı (Derinlemesine)
- Bölüm 5 — Konu 26: Recursion (Özyineleme)
- Bölüm 6 — Konu 27: Class Tanımlama, Constructor (Varsayılan, Named, Factory)
- Bölüm 6 — Konu 28: Alanlar (Fields), Metodlar, `this` Kullanımı (Derinlemesine)
- Bölüm 6 — Konu 29: Initializer List, Constructor Kısayolları (Derinlemesine)
- Bölüm 6 — Konu 30: Getter / Setter
- Bölüm 6 — Konu 31: Statik Üyeler (`static`)
- Bölüm 7 — Konu 32: Kalıtım (`extends`), `super` Kullanımı
- Bölüm 7 — Konu 33: Metod Override Etme, `@override`
- Bölüm 7 — Konu 34: Soyut Sınıflar (`abstract class`)
- Bölüm 7 — Konu 35: Interface Mantığı (`implements`)
- Bölüm 7 — Konu 36: Mixin (`with`)
- Bölüm 7 — Konu 37: `enum` — Basit ve Gelişmiş (Metotlu Enum'lar)
- Bölüm 8 — Konu 38: `try / catch / finally`, `throw`
- Bölüm 8 — Konu 39: Özel Exception Sınıfları Yazma
- Bölüm 8 — Konu 40: Sound Null Safety Derinlemesine — `late`, `required`, Non-Nullable Varsayılan Davranış
- Bölüm 8 — Konu 41: `assert` ile Geliştirme Zamanı Kontrolleri
- Bölüm 9 — Konu 42: Generic Sınıflar ve Fonksiyonlar
- Bölüm 9 — Konu 43: Generic Sınırlamalar (`<T extends ...>`)
- Bölüm 9 — Konu 44: Dart'ın Built-in Generic Koleksiyonları Nasıl Çalışır
- Bölüm 10 — Konu 45: `Future` Kavramı, `async`/`await`
- Bölüm 10 — Konu 46: `Future.then`, Hata Yönetimi (`catchError`)
- Bölüm 10 — Konu 47: `Stream` Temelleri, `async*`, `yield`
- Bölüm 10 — Konu 48: `StreamController`, Broadcast Stream
- Bölüm 11 — Konu 49: `map`, `where`, `reduce`, `fold`
- Bölüm 11 — Konu 50: `sort`, Custom Comparator ile Sıralama
- Bölüm 11 — Konu 51: Iterable Kavramı Derinlemesine (Lazy Evaluation)
- Bölüm 11 — Konu 52: Cascade Notasyonu (`..`)
- Bölüm 12 — Konu 53: `pubspec.yaml`, pub.dev'den Paket Ekleme
- Bölüm 12 — Konu 54: Kütüphane Oluşturma, `import`/`export`, `part`/`part of`
- Bölüm 12 — Konu 55: Dart'ta Test Yazımı (`test` Paketi, Unit Test Mantığı)
- Bölüm 12 — Konu 56: Extension Methods
- Bölüm 12 — Konu 57: Dart'ın Derleme Modelleri (JIT vs AOT) ve Bunun Flutter'a Etkisi
- Bölüm 13 — Konu 59: Dart 3 Pattern Matching — Records, Destructuring, Sealed Classes, Exhaustive Switch
- Bölüm 13 — Konu 60: `Never` Tipi, `covariant` ve Generic Variance Detayları
- Bölüm 13 — Konu 61: Event Loop Derinlemesine — Microtask Queue vs Event Queue
- Bölüm 13 — Konu 62: Memory Model & Performans — Garbage Collection, `const` Nesnelerin Bellek Avantajı
- Bölüm 13 — Konu 63: Isolate'ler Arası Mesajlaşmanın Maliyeti ve `compute()`'un İç İşleyişi
- Bölüm 13 — Konu 64: FFI (Foreign Function Interface) — C Koduna Erişim
- Bölüm 13 — Konu 65: Sunucu Tarafında Dart — `dart:io`, `shelf` Paketiyle Basit Bir Backend/CLI Aracı Yazma
- Bölüm 13 — Konu 66: Derleyici & Analiz Araçları — `dart analyze`, Custom Lint Kuralları, `build_runner` Mimarisi
İçindekiler 9 başlık
- Neden switch Var? if/else if Yetmiyor mu?
- Klasik switch İfadesi (Statement)
- break Neden Zorunlu? Dart'ta Fall-Through Aslında Yok
- Dart 3 — switch Expression (İfade Olarak Switch)
- Karşılaştırma — Ne Zaman Hangisi?
- Exhaustiveness (Kapsayıcılık) Kontrolü — Enum'larla Küçük Bir Önizleme
- Sayılarla switch Kullanımı
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler
Neden switch Var? if/else if Yetmiyor mu?
Teknik olarak her switch bir if/else if zinciriyle de yazılabilir. Ama tek bir değeri birden çok sabit değerle karşılaştıracağın durumlarda switch, hem daha okunabilir hem de (Dart 3 ile) derleyicinin eksik durumları sana haber vermesini sağlayan bir yapıdır.
Klasik switch İfadesi (Statement)
void main() {
String gun = "Pazartesi";
switch (gun) {
case "Pazartesi":
print("Haftanın ilk günü");
break;
case "Cumartesi":
case "Pazar":
print("Haftasonu");
break;
default:
print("Normal bir gün");
}
}Yapıyı parçalayalım:
switch (gun)— karşılaştırılacak değeri belirtir.case "Pazartesi":— değer bu case ile eşleşirse, altındaki kod çalışır.break;— bu case'in bittiğini belirtir.case "Cumartesi": case "Pazar":— birden fazla case, aralarında hiç kod olmadan art arda yazılırsa, aynı bloğu paylaşırlar (bu case'lerden herhangi biri eşleşirse aynı kod çalışır). Bu, aşağıda anlatılacak fall-through kuralının tek istisnasıdır.default:— hiçbir case eşleşmezse çalışacak yedek blok (elsegibi düşünebilirsin).
break Neden Zorunlu? Dart'ta Fall-Through Aslında Yok
C, Java veya JavaScript gibi dillere aşinaysan muhtemelen "fall-through" kavramını biliyorsundur: o dillerde bir case'in sonuna break koymazsan kontrol sessizce bir sonraki case'e "düşer" ve bu sık karşılaşılan bir hata kaynağıdır.
Dart bu davranışı baştan itibaren (bu bir Dart 3 değişikliği değil) engeller. Dart'ta, içinde kod bulunan (boş olmayan) bir case bloğu, break, continue, return veya throw gibi bir "çıkış" ifadesi olmadan bitiyorsa, bu bir derleme zamanı hatasıdır — kod hiç çalışmaz, hiç derlenmez. Yani aşağıdaki kod:
void main() {
int sayi = 1;
switch (sayi) {
case 1:
print("Bir");
// break yok!
case 2:
print("İki");
break;
default:
print("Diğer");
}
}derlenmez. Dart analizörü şuna benzer bir hata verir:
Error: The 'case' should end with a statement like 'break', 'continue', 'return' or 'throw'.
Try adding one of the statements before the next 'case'.Yani "önce yanlışlıkla iki satır yazdırılır, sonra derleyici bunu fark edip uyarır" gibi bir şey olmuyor — kod derlenme aşamasında reddediliyor, hiç çalışma şansı bulamıyor. Bu, Dart'ın C/Java tarzı dillerin en klasik hata kaynaklarından birini tasarım gereği ortadan kaldırdığı anlamına gelir: unutulan bir break senin projende sessiz bir bug olarak değil, derleyicinin anında durdurduğu bir hata olarak karşına çıkar.
Peki hiç fall-through yapamaz mısın? Yapabilirsin — ama bunun için kasıtlı ve açık olman gerekir. Dart, continue anahtar kelimesini bir case etiketiyle birlikte kullanmana izin verir:
void main() {
int sayi = 1;
switch (sayi) {
case 1:
print("Bir");
continue iki; // açıkça "case iki'ye devam et" diyoruz
iki:
case 2:
print("İki");
break;
default:
print("Diğer");
}
}Çıktı:
Bir
İkiBurada iki: bir etiket (label), case 2'nin hemen üstüne konmuş. continue iki; ifadesi derleyiciye "buradan case 2'ye bilerek geçiyorum, bu bir hata değil" diyor. Bu özellik nadiren kullanılır ama var olduğunu bilmen yeterli — pratikte çoğu zaman aynı işi case "Cumartesi": case "Pazar": örneğindeki gibi boş case birleştirme ile ya da fonksiyona çıkarma ile daha okunabilir şekilde çözersin.
Dart 3 — switch Expression (İfade Olarak Switch)
Dart 3 ile gelen en kullanışlı yeniliklerden biri: switch'i bir ifade (expression) olarak kullanabilmek, yani doğrudan bir değer üretip değişkene atayabilmek:
void main() {
String gun = "Pazartesi";
String mesaj = switch (gun) {
"Pazartesi" => "Haftanın ilk günü",
"Cumartesi" || "Pazar" => "Haftasonu",
_ => "Normal bir gün",
};
print(mesaj);
}Klasik switch statement ile farkları:
casekelimesi yok, doğrudan değer yazılır.:yerine=>kullanılır (arrow function'a benzer sözdizimi).breakgerekmez — her kol zaten tek bir değer üretir, fall-through riski yoktur.- Birden fazla değer için
||kullanılır (case "Cumartesi": case "Pazar":yerine"Cumartesi" || "Pazar" =>). defaultyerine_(alt çizgi, "her şeyi eşleştir" anlamında) kullanılır.- Sonunda virgülle biten her kol, bir sonraki koldan virgülle ayrılır.
Bu yeni sözdizimi, özellikle bir değer üretmek istediğinde (klasik switch'te olduğu gibi ayrı bir değişken tanımlayıp her case'de ona atama yapmak yerine) çok daha temiz bir kod sağlar.
Karşılaştırma — Ne Zaman Hangisi?
// Klasik switch statement — YAN ETKİ üretmek için (print, API çağrısı vb.)
void gunBilgisiYazdir(String gun) {
switch (gun) {
case "Pazartesi":
print("Toplantı günü");
break;
default:
print("Normal gün");
}
}
// switch expression — DEĞER üretmek için
String gunTipi(String gun) {
return switch (gun) {
"Cumartesi" || "Pazar" => "Haftasonu",
_ => "Haftaiçi",
};
}Genel kural: Eğer amacın bir değer üretip döndürmek ise (fonksiyondan return etmek, bir değişkene atamak), switch expression kullan — daha kısa ve güvenlidir. Eğer amacın birkaç farklı yan etki (side effect — print, API çağrısı, state değiştirme vb.) tetiklemekse, klasik switch statement daha uygun olabilir.
Exhaustiveness (Kapsayıcılık) Kontrolü — Enum'larla Küçük Bir Önizleme
Enum'ları henüz detaylı işlemedik (Bölüm 7'de göreceğiz) ama switch'in en güçlü yanlarından biri, enum'larla kullanıldığında ortaya çıkıyor:
enum TrafikIsigi { kirmizi, sari, yesil }
String eylemBelirle(TrafikIsigi isik) {
return switch (isik) {
TrafikIsigi.kirmizi => "Dur",
TrafikIsigi.sari => "Hazırlan",
TrafikIsigi.yesil => "Geç",
};
}Burada default (_) yazmadık — ve Dart buna izin veriyor çünkü TrafikIsigi enum'unun tüm olası değerlerini (kirmizi, sari, yesil) kapsadık. Eğer enum'a yeni bir değer eklenirse (örneğin TrafikIsigi.turuncu), Dart derleyicisi bu switch ifadesinin artık eksik (non-exhaustive) olduğunu sana derleme zamanında söyler — böylece unutkanlıktan kaynaklanan hataları baştan önler. Bu özelliği Dart 3'ün sealed class yapılarıyla birlikte Bölüm 13'te çok daha derinlemesine işleyeceğiz; bu sadece bir önizlemeydi.
Sayılarla switch Kullanımı
void main() {
int puan = 85;
String harfNotu = switch (puan) {
>= 90 => "AA",
>= 80 => "BA",
>= 70 => "BB",
>= 60 => "CB",
_ => "FF",
};
print(harfNotu); // BA
}Dikkat et — burada case değerleri artık sabit değil, >= 90 gibi bir karşılaştırma ifadesi. Bu da Dart 3'ün switch expression'a kazandırdığı güçlü bir özellik (pattern matching'in bir parçası) — klasik switch statement'ta bu mümkün değildi, sadece sabit değerlerle eşleştirme yapılabilirdi.
🎯 Bu Dersten Çıkarılması Gerekenler
- Klasik
switchstatement: içinde kod olan her case,break(veyacontinue/return/throw) ile bitmek zorundadır — bunu atlamak Dart'ta çalışma zamanı hatası değil, derleme zamanı hatasıdır. Bu, Dart 3'e özgü değil, dilin en başından beri var olan bir kuraldır. - Sessiz fall-through Dart'ta yoktur; kasıtlı fall-through istersen
continue etiketliCase;sözdizimini açıkça kullanman gerekir. - Art arda gelen tamamen boş case'ler (
case "Cumartesi": case "Pazar":) aynı bloğu paylaşabilir — bu fall-through değil, birden fazla case'i tek bir sonuca bağlamanın kasıtlı bir yoludur. - Dart 3
switchexpression:=>ile değer üretir,_ile varsayılan durum,||ile çoklu eşleşme. - Değer üretmek için
switchexpression, yan etki tetiklemek için klasikswitchstatement tercih edilir. - Enum'larla kullanıldığında, tüm değerler kapsandığında
defaultgerekmez ve derleyici eksik durumları yakalar (exhaustiveness). switchexpression'da karşılaştırma ifadeleri (>= 90gibi) de kullanılabilir.
📝 Ödevler
- [ ] Bir haftanın günlerini (
"Pazartesi"'den"Pazar"'a) alıp haftaiçi/haftasonu ayrımı yapan hem klasikswitchstatement hem deswitchexpression versiyonunu yaz, ikisini karşılaştır. - [ ] Bilerek bir case'in sonuna
breakkoymadan derlemeyi dene ve derleyicinin sana verdiği hata mesajını oku — ardındancontinue etiketliCase;sözdizimiyle kasıtlı bir fall-through örneği yaz. - [ ] Bir notu (0-100) alıp harf notuna çeviren
switchexpression'ı, karşılaştırma ifadeleriyle (>= 90gibi) yaz. - [ ] Basit bir enum (örn. mevsimler:
ilkbahar, yaz, sonbahar, kis) tanımla, her mevsim için bir mesaj döndüren exhaustive birswitchexpression yaz —defaultkullanmadan.
Sıradaki konu: Bölüm 3 — Konu 13: Ternary Operatör, ??, ??=, ?.