Bölüm 3 — Konu 13: Ternary Operatör, `??`, `??=`, `?.`
Dizi · 13/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 8 başlık
Bu derste, daha önce bazılarına kısaca değindiğimiz operatörleri toparlayıp derinlemesine işleyeceğiz — bunlar Dart kodunda gerçekten çok sık karşına çıkacak, o yüzden rahat kullanabilmen önemli.
Ternary Operatör (? :) — Koşullu İfade
Bölüm 3 Konu 11'de kısaca önizlemesini görmüştük, şimdi tam olarak işleyelim:
void main() {
int yas = 20;
String durum = yas >= 18 ? "Reşit" : "Reşit değil";
print(durum); // Reşit
}Sözdizimi: koşul ? koşulTrueİseDeğer : koşulFalseİseDeğer
Bu, kısa if/else'in yerine geçer — ama sadece bir değer üretmek istediğinde kullanılır, yan etki (print, fonksiyon çağrısı vb.) için değil (teknik olarak mümkün ama önerilmez, birazdan göreceğiz).
İç içe ternary — dikkatli kullanılmalı:
void main() {
int not = 75;
String harfNotu = not >= 90
? "AA"
: not >= 80
? "BA"
: not >= 70
? "BB"
: "FF";
print(harfNotu); // BB
}Bu çalışır ama okunabilirliği hızla düşer. Genel kural: ternary'yi tek seviyede tut. Birden fazla koşul zincirlemen gerekiyorsa, bir önceki derste gördüğümüz switch expression çok daha okunabilir bir alternatiftir:
void main() {
int not = 75;
String harfNotu = switch (not) {
>= 90 => "AA",
>= 80 => "BA",
>= 70 => "BB",
_ => "FF",
};
print(harfNotu); // BB
}Ternary'yi yan etki için kullanmak — kaçınılması gereken bir pratik:
void main() {
bool girisYapildi = true;
// ❌ Kötü pratik — ternary bir değer üretmiyor, sadece yan etki tetikliyor
girisYapildi ? print("Hoş geldin") : print("Lütfen giriş yapın");
// ✅ Doğrusu — yan etki için if/else kullan
if (girisYapildi) {
print("Hoş geldin");
} else {
print("Lütfen giriş yapın");
}
}İlk örnek teknik olarak çalışır ama ternary'nin amacı bu değil — bu kullanım, kodu okuyanları yanıltabilir ("bu bir değer mi üretiyor, yoksa sadece yan etki mi?" sorusunu akla getirir).
?? — Null Coalescing (Null Birleştirme) Operatörü
Bölüm 2'de null safety konusunda görmüştük, burada pekiştirelim:
void main() {
String? takmaAd;
String gercekAd = "Ahmet";
String gosterilecekAd = takmaAd ?? gercekAd;
print(gosterilecekAd); // Ahmet — çünkü takmaAd null
takmaAd = "Ahi";
String gosterilecekAd2 = takmaAd ?? gercekAd;
print(gosterilecekAd2); // Ahi — artık takmaAd null değil
}Sözdizimi: solTaraf ?? sağTaraf → sol taraf null değilse sol tarafı, null ise sağ tarafı kullanır.
Zincirleme kullanım:
void main() {
String? a;
String? b;
String c = "Varsayılan";
String sonuc = a ?? b ?? c;
print(sonuc); // Varsayılan — hem a hem b null, sırayla kontrol edilip sonunda c kullanılır
}??= — Null İse Ata (Null-Aware Assignment)
void main() {
String? kullaniciAdi;
kullaniciAdi ??= "Misafir"; // kullaniciAdi null olduğu için "Misafir" atanır
print(kullaniciAdi); // Misafir
kullaniciAdi ??= "BaşkaBirİsim"; // kullaniciAdi artık null değil, atama YAPILMAZ
print(kullaniciAdi); // Misafir (değişmedi!)
}Sözdizimi: degisken ??= deger → degisken null ise deger'i ata, null değilse hiçbir şey yapma.
Bu, şu uzun yazımın kısayoludur:
if (kullaniciAdi == null) {
kullaniciAdi = "Misafir";
}??= genelde "eğer bu değişkene henüz bir değer atanmadıysa, varsayılan bir değer ata" senaryolarında kullanılır — örneğin bir önbellek (cache) mekanizmasında ilk erişimde değeri hesaplayıp saklamak gibi.
?. — Null-Aware Erişim Operatörü (Tekrar, Derinlemesine)
Bölüm 2'de görmüştük, burada daha karmaşık senaryolarla pekiştirelim:
void main() {
String? isim = "Ahmet";
print(isim?.length); // 5
isim = null;
print(isim?.length); // null — hata vermez
}Zincirleme ?. kullanımı:
class Adres {
String? sehir;
Adres({this.sehir});
}
class Kullanici {
Adres? adres;
Kullanici({this.adres});
}
void main() {
Kullanici kullanici = Kullanici(adres: Adres(sehir: "İstanbul"));
print(kullanici.adres?.sehir); // İstanbul
Kullanici kullanici2 = Kullanici(); // adres yok
print(kullanici2.adres?.sehir); // null — hata vermez, zincir güvenli şekilde kırılır
}Sınıfları henüz detaylı işlemedik (Bölüm 6) ama bu örnek, ?.'nin gerçek gücünü gösteriyor: zincirleme erişimlerde, herhangi bir noktada null olursa, tüm zincir güvenli şekilde null sonucuna düşer — tek tek if (x != null) kontrolleri yazmana gerek kalmaz.
Bu Operatörleri Birlikte Kullanmak
Gerçek kodda bu operatörler genelde birlikte kullanılır:
class Kullanici {
String? takmaAd;
Kullanici({this.takmaAd});
}
void main() {
Kullanici? kullanici = Kullanici(takmaAd: "Ahi");
String gosterilecekIsim = kullanici?.takmaAd ?? "Misafir";
print(gosterilecekIsim); // Ahi
kullanici = null;
String gosterilecekIsim2 = kullanici?.takmaAd ?? "Misafir";
print(gosterilecekIsim2); // Misafir
}Bu satır — kullanici?.takmaAd ?? "Misafir" — çok yaygın bir Dart/Flutter kalıbıdır: "Eğer kullanıcı varsa ve takma adı varsa onu göster, yoksa (herhangi bir noktada null ise) 'Misafir' göster." Bunu ileride Flutter'da kullanıcı profili gösteren widget'larda sürekli göreceksin.
Özet Karşılaştırma Tablosu
| Operatör | Ne İşe Yarar | Örnek |
|---|---|---|
? : (ternary) |
Koşula göre iki değerden birini seçer | yas >= 18 ? "Reşit" : "Değil" |
?? |
Null ise varsayılan değer kullanır | isim ?? "Misafir" |
??= |
Null ise değişkene ata (değilse dokunma) | isim ??= "Misafir" |
?. |
Null ise erişimi atlar, sonucu null yapar | kullanici?.isim |
🎯 Bu Dersten Çıkarılması Gerekenler
- Ternary (
? :) kısaif/elsegibidir, değer üretmek için kullanılır; yan etki içinif/elsetercih edilmeli. - İç içe ternary okunabilirliği düşürür — birden fazla koşul için
switchexpression daha uygun. ??: null ise varsayılan değer sağlar, zincirlenebilir (a ?? b ?? c).??=: null ise ata, değilse dokunma.?.: zincirleme erişimlerde herhangi bir noktada null olursa güvenli şekildenullsonucuna düşer.kullanici?.alan ?? "varsayılan"kalıbı, Dart/Flutter'da çok sık kullanılan bir desendir.
📝 Ödevler
- [ ] Bir yaşı kontrol edip ternary ile "Reşit"/"Reşit değil" döndüren bir örnek yaz.
- [ ] Aynı örneği bilerek 3 seviyeli iç içe ternary ile yazıp okunabilirliğinin nasıl düştüğünü gözlemle, sonra
switchexpression ile tekrar yaz. - [ ] Nullable bir değişkenle
??=kullanarak "sadece ilk kez null ise ata" davranışını iki farklı atama denemesiyle göster. - [ ] Nullable bir sınıf alanı zincirinde (örn.
kullanici?.adres?.sehir) en az iki seviyeli?.kullanarak güvenli erişim örneği yaz (sınıfları detaylı işlemedik ama basit bir örnek deneyebilirsin). - [ ]
kullanici?.takmaAd ?? "Misafir"kalıbını kullanan, hem kullanıcı hem takma ad null olduğunda hem de olmadığında test eden bir örnek yaz.
Sıradaki konu: Bölüm 3 — Konu 14: for, while, do-while Döngüleri