Bölüm 9 — Konu 44: Dart'ın Built-in Generic Koleksiyonları Nasıl Çalışır
Dizi · 43/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 10 başlık
- List<T> — Basitleştirilmiş Bir Zihin Modeli
- operator [] — Küçük Bir Not
- Map<K, V> — İki Tip Parametreli Generic
- Koleksiyon Tipleri Arasında Uyumluluk — Kovaryans (Kısa Bir Bakış)
- is ile Generic Tip Kontrolü
- List<Object> vs List<dynamic> — İnce Bir Fark
- Neden Bu Konuyu Bilmek Önemli?
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler
- 🏁 Bölüm 9 Tamamlandı!
Bölüm 9'un son konusundayız. Şimdiye kadar generics'i kendi sınıflarımızda kullanmayı gördük. Bu derste, Bölüm 4'te öğrendiğimiz List, Set, Map'in aslında birer generic sınıf olarak nasıl tasarlandığını anlayacağız.
List<T> — Basitleştirilmiş Bir Zihin Modeli
Dart'ın gerçek List implementasyonu çok daha karmaşıktır (performans optimizasyonları, farklı liste türleri vb. içerir), ama kavramsal olarak şöyle düşünebilirsin:
// Bu, GERÇEK List implementasyonu DEĞİL — sadece kavramı anlamak için basitleştirilmiş bir örnek
class BenimListem<T> {
final List<T> _icerik = [];
void add(T eleman) {
_icerik.add(eleman);
}
T operator [](int index) {
return _icerik[index];
}
int get length => _icerik.length;
}
void main() {
BenimListem<String> liste = BenimListem();
liste.add("Merhaba");
print(liste[0]); // Merhaba
print(liste.length); // 1
}Bu örnek, Bölüm 9'da öğrendiğin generic sınıf kavramının, Dart'ın kendi List<T> sınıfında da aynı prensiple çalıştığını gösteriyor. List<String> yazdığında, aslında List sınıfının T tip parametresine String "geçiriyorsun" — tıpkı kendi Kutu<T> sınıfını kullandığın gibi.
operator [] — Küçük Bir Not
Yukarıdaki örnekte T operator [](int index) gördün — bu, operatör overloading dediğimiz, ileri bir Dart özelliğidir ([] erişim operatörünü kendi sınıfın için özelleştirmeni sağlar). Bunu şimdi detaylı işlemiyoruz, sadece liste[0] gibi bir erişimin arka planda bir metod çağrısı olduğunu bilmen, generics'in koleksiyonlarda nasıl işlediğini anlaman için yeterli.
Map<K, V> — İki Tip Parametreli Generic
Bölüm 9 Konu 42'de gördüğümüz Cift<A, B> örneğini hatırlarsan, Map<K, V> de aynı mantıkla çalışır — sadece çok daha gelişmiş bir implementasyona sahiptir (hash tabanlı arama için optimize edilmiştir):
// Kavramsal basitleştirme
class BenimMapim<K, V> {
final Map<K, V> _icerik = {};
void set(K anahtar, V deger) {
_icerik[anahtar] = deger;
}
V? get(K anahtar) {
return _icerik[anahtar];
}
}
void main() {
BenimMapim<String, int> yaslar = BenimMapim();
yaslar.set("Ahmet", 25);
print(yaslar.get("Ahmet")); // 25
}K (Key) ve V (Value), Bölüm 9'da öğrendiğimiz "birden fazla tip parametresi" kavramının Dart'ın kendi kütüphanesindeki gerçek kullanımıdır.
Koleksiyon Tipleri Arasında Uyumluluk — Kovaryans (Kısa Bir Bakış)
void main() {
List<int> tamSayilar = [1, 2, 3];
List<num> sayilar = tamSayilar; // ✅ çalışır! List<int>, List<num>'a atanabilir
print(sayilar); // [1, 2, 3]
}Bu ilginç bir davranış — List<int>, List<num> tipine atanabiliyor, çünkü Bölüm 2'de gördüğümüz gibi int, num'un bir alt tipidir. Bu davranışa kovaryans (covariance) denir — "eğer int, num'un alt tipiyse, List<int> da List<num>'ın alt tipi sayılır" mantığı. Bunu tam olarak Bölüm 13'te (variance detayları) işleyeceğiz — şimdilik sadece bu davranışın var olduğunu ve bazen beklenmedik sonuçlara yol açabileceğini bilmen yeterli:
void main() {
List<int> tamSayilar = [1, 2, 3];
List<num> sayilar = tamSayilar;
sayilar.add(3.14); // ❌ RUNTIME HATASI! Aslında altta yatan liste hâlâ List<int>
}Bu, ileri bir tuzak — sayilar değişkeni List<num> tipinde görünse de, altında yatan gerçek nesne hâlâ List<int>'tir, bu yüzden ona bir double eklemeye çalışmak çalışma zamanında hataya yol açar. Bu konuyu şimdilik sadece farkında olman için gösteriyoruz; derinlemesine Bölüm 13'te işleyeceğiz.
is ile Generic Tip Kontrolü
void main() {
List<String> isimler = ["Ahmet", "Ayşe"];
List<int> sayilar = [1, 2, 3];
print(isimler is List<String>); // true
print(isimler is List<int>); // false
print(isimler is List); // true — tip parametresi belirtilmeden de kontrol edilebilir
}Bölüm 3'te öğrendiğimiz is operatörü, generic koleksiyonlarla da çalışır — hem tam tip eşleşmesi (List<String>) hem de genel tip kontrolü (List) yapabilirsin.
List<Object> vs List<dynamic> — İnce Bir Fark
void main() {
List<Object> objeListesi = [1, "iki", true]; // karışık tipler, ama hepsi Object
List<dynamic> dinamikListe = [1, "iki", true]; // aynı görünüyor ama...
for (var eleman in objeListesi) {
// eleman, Object tipinde — sadece Object'in metodları doğrudan çağrılabilir
print(eleman.toString());
}
for (var eleman in dinamikListe) {
// eleman, dynamic tipinde — HERHANGİ bir metod çağrılabilir (riskli!)
print(eleman.toString());
}
}Bölüm 2'de öğrendiğimiz Object ile dynamic arasındaki fark, koleksiyonlarda da aynen geçerlidir: List<Object>, her elemanın en azından Object olduğunu garanti eder (tip güvenli), List<dynamic> ise tip kontrolünü tamamen kapatır. JSON gibi karışık tipli veri yapılarıyla çalışırken, List<dynamic> yerine mümkünse List<Object?> kullanmak daha güvenlidir — ama bu, projenin ihtiyacına göre değişebilir.
Neden Bu Konuyu Bilmek Önemli?
Flutter'da, özellikle API'lerden gelen JSON verisiyle çalışırken (List<dynamic>, Map<String, dynamic> gibi tiplerle sıkça karşılaşacaksın — Bölüm 5'in ilerleyen konularında bunu tam olarak işleyeceğiz), bu generics bilgisi, neden bu tiplerin bu şekilde tasarlandığını ve hangi durumda hangi tipin daha güvenli olduğunu anlamana yardımcı olacak.
🎯 Bu Dersten Çıkarılması Gerekenler
- Dart'ın
List<T>,Map<K, V>,Set<T>koleksiyonları, kendi yazdığın generic sınıflarla aynı temel prensiple tasarlanmıştır. - Kovaryans,
List<int>'inList<num>'a atanabilmesini sağlar, ama bu bazı runtime hatalarına yol açabilir (Bölüm 13'te derinlemesine işlenecek). is, generic koleksiyonlarla tam tip (List<String>) veya genel tip (List) kontrolü için kullanılabilir.List<Object>, tip güvenliğini korur;List<dynamic>, tip kontrolünü kapatır — JSON gibi karışık verilerle çalışırken bu farkı bilmek önemlidir.
📝 Ödevler
- [ ] Kendi basit bir generic "liste benzeri" sınıfını yaz (add, length, [] erişimi ile), Bölüm 9 boyunca öğrendiklerini pekiştir.
- [ ]
List<int>'iList<num>'a atayıp, sonra bu değişkene birdoubleeklemeyi dene, runtime hatasını gözlemle ve yorumla. - [ ]
isoperatörü ile en az 3 farklı generic koleksiyon tipini (List<String>,Map<String, int>, genelList) kontrol eden bir örnek yaz. - [ ] Aynı verilerle bir
List<Object>ve birList<dynamic>oluştur, aralarındaki tip güvenliği farkını, bilerek yanlış bir metod çağırarak göster. - [ ] Kendi cümlelerinle, "Dart'ın List ve Map sınıfları neden generic olarak tasarlandı" sorusunu, Bölüm 9'da öğrendiklerinle açıkla.
🏁 Bölüm 9 Tamamlandı!
Generics'in temellerini, sınırlamalarını ve Dart'ın kendi koleksiyonlarının bunları nasıl kullandığını öğrendik. Bu, hem kendi esnek ve tip-güvenli sınıflarını yazabilmeni hem de Dart'ın standart kütüphanesini çok daha derinlemesine anlamanı sağladı.
Sıradaki durak Bölüm 10 — Asenkron Programlama: Future, async/await, Stream ile Dart'ın zamanla ilgili (zaman alan, beklemeli) işlemleri nasıl yönettiğini işleyeceğiz — bu, Flutter'da API çağrıları yaparken mutlaka bilmen gereken bir konu.