Bölüm 12 — Konu 56: Extension Methods
Dizi · 55/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 11 başlık
- Sorun: Var Olan Bir Sınıfa Nasıl Metod Eklersin?
- Extension Tanımlama
- Extension İçinde this Kullanımı
- Kendi Sınıflarına Extension Ekleme
- Neden Urun Sınıfının İçine Yazmıyoruz? — Ayrım Nedeni
- Birden Fazla Extension — Çakışma Durumu
- Extension'lar Nesnenin Kendisini Değiştiremez
- Nullable Tipler Üzerinde Extension
- Gerçek Dünya Kullanımı — Flutter Bağlantısı
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler
Sorun: Var Olan Bir Sınıfa Nasıl Metod Eklersin?
Diyelim ki String sınıfına, ilk harfini büyük yapan bir metod eklemek istiyorsun. Ama Bölüm 7'de öğrendiğimiz gibi, String Dart'ın kendi kütüphanesinde tanımlı — onun kaynak koduna doğrudan erişimin yok, extends String de yapamazsın (çünkü String'in kendi iç yapısı buna izin vermez).
void main() {
String isim = "ahmet";
print(isim.capitalize()); // ❌ Böyle bir metod yok!
}Extension methods, tam olarak bu problemi çözmek için var: var olan herhangi bir sınıfa (kendi yazdığın veya Dart'ın kendi sınıfları), yeni metodlar "ekleyebilmeni" sağlar — sınıfın kendisini değiştirmeden.
Extension Tanımlama
extension StringUzantilari on String {
String capitalize() {
if (isEmpty) return this;
return this[0].toUpperCase() + substring(1);
}
}
void main() {
String isim = "ahmet";
print(isim.capitalize()); // Ahmet
}Sözdizimi: extension UzantiAdi on HedefTip { ... }
StringUzantilari— extension'ın adı (isteğe bağlı, ama koyman önerilir — adsız extension'lar da yazılabilir, birazdan göreceğiz).on String— bu extension'ın hangi tipe uygulandığını belirtir.- İçindeki metodlar, sanki
Stringsınıfının kendi metodlarıymış gibi çağrılabilir hale gelir.
Extension İçinde this Kullanımı
extension StringUzantilari on String {
String tersCevir() {
return String.fromCharCodes(this.runes.toList().reversed);
}
}
void main() {
print("merhaba".tersCevir()); // abahrem
}Extension metodu içinde this, extension'ın uygulandığı nesnenin kendisini temsil eder (burada, çağrıldığı String'i) — Bölüm 6'da öğrendiğimiz this kullanımıyla aynı mantık, sadece burada "kendi sınıfın" değil, "genişlettiğin" sınıfın bir örneğine işaret ediyor.
Kendi Sınıflarına Extension Ekleme
Extension'lar sadece Dart'ın kendi sınıfları için değil, senin yazdığın sınıflar için de kullanılabilir — bu, özellikle bir sınıfa her zaman erişimin olmadığı durumlarda (örneğin başka bir kütüphaneden gelen bir sınıf) veya sınıfın ana tanımını sade tutmak istediğinde kullanışlıdır:
class Urun {
String ad;
double fiyat;
Urun(this.ad, this.fiyat);
}
extension UrunUzantilari on Urun {
String get formatliFiyat => "${fiyat.toStringAsFixed(2)} TL";
bool get indirimdeMi => fiyat < 50;
}
void main() {
Urun urun = Urun("Kalem", 15.5);
print(urun.formatliFiyat); // 15.50 TL
print(urun.indirimdeMi); // true
}Bölüm 6'da öğrendiğimiz getter kavramını, extension içinde de kullanabildiğimizi görüyorsun — extension'lar, metodların yanında getter/setter da tanımlayabilir.
Neden Urun Sınıfının İçine Yazmıyoruz? — Ayrım Nedeni
// Alternatif: doğrudan sınıfın içinde
class Urun {
String ad;
double fiyat;
Urun(this.ad, this.fiyat);
String get formatliFiyat => "${fiyat.toStringAsFixed(2)} TL"; // burada da tanımlanabilirdi
}Bu, teknik olarak da geçerlidir — peki extension'ın avantajı ne? İki temel senaryo:
- Sınıfın kaynak koduna erişimin yoksa (örneğin bir paketten gelen bir sınıf,
Stringgibi Dart'ın kendi sınıfları) — extension, tek çözümdür. - Sınıfın "temel" tanımını, ona ait farklı "yeteneklerden" ayırmak istiyorsan — örneğin bir
Urunsınıfının temel veri yapısı bir dosyada, "gösterim mantığı" (formatlama gibi) ayrı bir dosyada extension olarak tutulabilir. Bu, Bölüm 12 Konu 54'te öğrendiğimiz dosya organizasyonu mantığına benzer bir ayrım sağlar.
Birden Fazla Extension — Çakışma Durumu
extension A on String {
String selamla() => "A: Merhaba $this";
}
extension B on String {
String selamla() => "B: Merhaba $this";
}
void main() {
print("Ahmet".selamla()); // ❌ HATA! Birden fazla extension aynı metodu tanımlıyor, belirsiz
}Eğer aynı tipte, aynı isimli metod tanımlayan iki extension aynı anda kullanılabilir durumdaysa (ikisi de import edilmişse), Dart hangisini çağıracağını bilemez ve hata verir. Bu durumda, hangi extension'ı kastettiğini açıkça belirtmen gerekir:
void main() {
print(A("Ahmet").selamla()); // A extension'ını açıkça belirt
}Bu senaryo nadir karşına çıkar (genelde farklı paketlerden gelen extension'lar çakıştığında), ama var olduğunu bilmen faydalı.
Extension'lar Nesnenin Kendisini Değiştiremez
extension SayiUzantisi on int {
void ikiyeKatla() {
this = this * 2; // ❌ HATA! 'this' değiştirilemez
}
}Extension metodları, yeni bir değer döndürebilir ama çağrıldıkları nesneyi doğrudan değiştiremez (mutate edemez) — çünkü extension'lar, aslında arka planda statik fonksiyonlar gibi çalışır (Bölüm 6'da öğrendiğimiz static kavramına benzer bir mekanizma), gerçek bir kalıtım veya nesne değişikliği söz konusu değildir:
extension SayiUzantisi on int {
int ikiyeKatla() => this * 2; // ✅ doğrusu — yeni bir değer DÖNDÜR
}
void main() {
int sayi = 5;
int sonuc = sayi.ikiyeKatla();
print(sonuc); // 10
print(sayi); // 5 — orijinal değer değişmedi!
}Nullable Tipler Üzerinde Extension
extension NullableStringUzantisi on String? {
bool get boşMuYaDaNull => this == null || this!.isEmpty;
}
void main() {
String? isim1 = null;
String? isim2 = "";
String? isim3 = "Ahmet";
print(isim1.boşMuYaDaNull); // true
print(isim2.boşMuYaDaNull); // true
print(isim3.boşMuYaDaNull); // false
}Bölüm 2'de öğrendiğimiz null safety, extension'larla da uyumlu çalışır — on String? yazarak, extension'ı nullable bir tip üzerinde de tanımlayabilirsin. Bu, null kontrolü içeren yardımcı metodlar yazmak için kullanışlıdır (yukarıdaki örnek, ??/?.'ye ek bir kolaylık sağlıyor).
Gerçek Dünya Kullanımı — Flutter Bağlantısı
Extension'lar, Flutter geliştirmede son derece yaygındır — örneğin BuildContext (Flutter'ın temel bir sınıfı) üzerine, ekran boyutunu almak, tema renklerine kolayca erişmek gibi extension'lar yazmak çok sık karşılaşacağın bir pratiktir. Bunu Flutter tutorial'ında somut örneklerle göreceğiz; burada öğrendiğin temel mekanizma, orada doğrudan işine yarayacak.
🎯 Bu Dersten Çıkarılması Gerekenler
- Extension methods, var olan bir sınıfa (kendi sınıfların veya Dart'ın kendi sınıfları) yeni metod/getter/setter eklemeni sağlar, sınıfın kendisini değiştirmeden.
extension Ad on Tip { ... }sözdizimiyle tanımlanır; içindethis, genişletilen nesnenin kendisini temsil eder.- Extension'lar, nesneyi doğrudan değiştiremez — her zaman yeni bir değer döndürmelidir.
- Aynı tipte, aynı isimli birden fazla extension çakışırsa, hangisinin kullanılacağını açıkça belirtmen gerekir.
- Nullable tipler üzerinde de extension tanımlanabilir (
on String?gibi). - Flutter geliştirmede, özellikle
BuildContextgibi çekirdek sınıflara ek kolaylıklar eklemek için çok sık kullanılır.
📝 Ödevler
- [ ]
Stringsınıfına, bir cümledeki her kelimenin ilk harfini büyük yapan bir extension metodu yaz (capitalizeWords()gibi). - [ ] Kendi yazdığın bir sınıfa (örn.
Urun), en az bir metod ve bir getter içeren bir extension ekle. - [ ]
intsınıfına, bir sayının asal olup olmadığını kontrol eden bir extension metodu yaz. - [ ] Nullable bir tip üzerinde (
on int?gibi) bir extension tanımla, null kontrolü içeren kullanışlı bir getter/metod ekle. - [ ] Extension'ın nesneyi değiştiremediğini (sadece yeni değer döndürebildiğini) kanıtlayan bir örnek yaz — önce yanlış (mutate etmeye çalışan) bir versiyon dene, hatayı gözlemle, sonra doğru (yeni değer döndüren) versiyonu yaz.
Sıradaki konu: Bölüm 12 — Konu 57: Dart'ın Derleme Modelleri (JIT vs AOT) ve Bunun Flutter'a Etkisi