Bölüm 5 — Konu 25: Anonim Fonksiyonlar ve Closure Kavramı (Derinlemesine)
Dizi · 24/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
- Closure Nedir?
- Her Çağrı Kendi Closure'ını Oluşturur
- Closure'ın Pratik Kullanım Alanları
- 1. Özelleştirilmiş Fonksiyonlar Üretme
- 2. Callback Fonksiyonlarda Dış Değişkenlere Erişim
- 3. State (Durum) Saklama — Flutter'a Doğrudan Bağlantı
- Closure ile Değişken Yakalama — Dikkat Edilmesi Gereken Bir Nokta
- final/const ile Closure İlişkisi
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler
- 🏁 Bölüm 5'in Beşinci Konusu Tamamlandı!
Önceki derste anonim fonksiyonları ve bir fonksiyonun başka bir fonksiyon döndürebildiğini görmüştük. Bu derste, o örnekte gizlice karşımıza çıkan ama üzerinde durmadığımız çok önemli bir kavramı derinlemesine işleyeceğiz: closure.
Closure Nedir?
Closure, bir fonksiyonun, tanımlandığı ortamdaki (scope) değişkenleri "hatırlaması" ve o değişkenlere erişebilmesi durumudur — fonksiyon çalıştırıldığı yerden çok uzakta olsa bile.
Bunu somut bir örnekle görelim:
Function sayacOlustur() {
int sayac = 0; // bu değişken, sayacOlustur'un LOKAL scope'unda
int sayacArtir() {
sayac++; // dıştaki 'sayac' değişkenine erişiyor
return sayac;
}
return sayacArtir; // fonksiyonu döndürüyoruz (henüz çağırmadan)
}
void main() {
var sayac1 = sayacOlustur();
print(sayac1()); // 1
print(sayac1()); // 2
print(sayac1()); // 3 — her çağrıda sayac değeri KORUNUYOR ve artıyor!
}Burada olağanüstü olan ne? Normalde, bir fonksiyon çalışmasını bitirdiğinde, o fonksiyonun içindeki lokal değişkenler (sayac gibi) bellekten silinir. Ama burada sayacOlustur() çalışmasını bitirmiş olmasına rağmen, döndürdüğü sayacArtir fonksiyonu hâlâ sayac değişkenine erişebiliyor ve onu güncelleyebiliyor. Bu, sayacArtir'ın bir closure oluşturduğu anlamına gelir — kendi tanımlandığı ortamın (sayac değişkenini içeren scope) bir "kapsülünü" (closure) yanında taşıyor.
Her Çağrı Kendi Closure'ını Oluşturur
void main() {
var sayac1 = sayacOlustur();
var sayac2 = sayacOlustur(); // AYRI bir çağrı, AYRI bir closure
print(sayac1()); // 1
print(sayac1()); // 2
print(sayac2()); // 1 — sayac2'nin kendi bağımsız sayacı var, sayac1'den etkilenmedi!
print(sayac1()); // 3 — sayac1 kendi sayacına devam ediyor
}
Function sayacOlustur() {
int sayac = 0;
return () {
sayac++;
return sayac;
};
}Bu, closure'ların en önemli özelliğidir: her fonksiyon çağrısı, kendi bağımsız değişken kopyasını "kilitler" (closure oluşturur). sayac1 ve sayac2, aynı sayacOlustur fonksiyonundan üretilmiş olsalar da, birbirinden tamamen bağımsız çalışırlar.
Closure'ın Pratik Kullanım Alanları
1. Özelleştirilmiş Fonksiyonlar Üretme
Function carpanOlustur(int carpan) {
return (int sayi) => sayi * carpan;
}
void main() {
var ikiyleCarpan = carpanOlustur(2);
var onlaCarpan = carpanOlustur(10);
print(ikiyleCarpan(5)); // 10
print(onlaCarpan(5)); // 50
}Burada carpan parametresi, döndürülen anonim fonksiyon tarafından "hatırlanıyor" — her üretilen fonksiyon, kendi carpan değerine sahip, birbirinden bağımsız bir closure.
2. Callback Fonksiyonlarda Dış Değişkenlere Erişim
void main() {
String kullaniciAdi = "Ahmet";
List<int> sayilar = [1, 2, 3];
sayilar.forEach((sayi) {
print("$kullaniciAdi için sayı: $sayi"); // dıştaki kullaniciAdi'ye erişiyor
});
}Bu, aslında closure'ın en sık karşına çıkacağı kullanım şeklidir — anonim bir fonksiyon (burada forEach'e geçirilen), kendi dışındaki bir değişkene (kullaniciAdi) doğrudan erişebiliyor, parametre olarak almasına bile gerek kalmadan.
3. State (Durum) Saklama — Flutter'a Doğrudan Bağlantı
Function butonSayaci() {
int tiklamaSayisi = 0;
return () {
tiklamaSayisi++;
print("Tıklama sayısı: $tiklamaSayisi");
};
}
void main() {
var buton1Tikla = butonSayaci();
buton1Tikla(); // Tıklama sayısı: 1
buton1Tikla(); // Tıklama sayısı: 2
buton1Tikla(); // Tıklama sayısı: 3
}Bu kalıp, ileride Flutter'da onPressed: () { setState(() { sayac++; }); } gibi yapılar yazarken karşına çıkacak mantığın temelidir — bir buton her tıklandığında çalışacak fonksiyon, kendi dışındaki bir durumu (state) "hatırlayıp" güncelleyebiliyor.
Closure ile Değişken Yakalama — Dikkat Edilmesi Gereken Bir Nokta
void main() {
List<Function> fonksiyonlar = [];
for (int i = 0; i < 3; i++) {
fonksiyonlar.add(() => print(i));
}
for (var f in fonksiyonlar) {
f();
}
// Çıktı: 0, 1, 2
}Dart'ta her for iterasyonu, i için yeni bir kopya oluşturur (bu davranış dilden dile değişebilir — örneğin bazı eski JavaScript sürümlerinde var ile bu farklı çalışırdı, hepsi son değeri yazardı). Dart'ta bu doğru ve beklenen şekilde çalışır: her closure, oluşturulduğu anki i değerini doğru şekilde yakalar.
final/const ile Closure İlişkisi
Bölüm 2'de öğrendiğimiz final/const kavramları, closure'larla birlikte kullanıldığında da tutarlı davranır — bir closure, dış scope'taki bir final değişkenin değerini "yakaladığında", o değer değişmeyeceği için closure'ın davranışı da öngörülebilir olur. var ile tanımlanan ve closure içinde güncellenen değişkenlerde ise (yukarıdaki sayaç örneklerinde gördüğümüz gibi) değer gerçekten değişebilir — bu, closure'ın "canlı bir referans" tuttuğunu, "o anki değerin bir kopyasını" tutmadığını gösterir.
🎯 Bu Dersten Çıkarılması Gerekenler
- Closure, bir fonksiyonun tanımlandığı ortamdaki değişkenlere, o ortam "kapanmış" (fonksiyon çalışmasını bitirmiş) olsa bile erişebilmesidir.
- Her fonksiyon çağrısı kendi bağımsız closure'ını oluşturur — farklı çağrılar birbirinin durumunu etkilemez.
- Closure'lar, özelleştirilmiş fonksiyonlar üretmek, callback'lerde dış değişkenlere erişmek ve durum (state) saklamak için kullanılır.
- Dart'ta
fordöngülerinde her iterasyon kendi değişken kopyasını doğru şekilde closure'a yakalar. - Bu kavram, ileride Flutter'da state yönetimi ve callback fonksiyonları anlarken doğrudan işine yarayacak.
📝 Ödevler
- [ ]
sayacOlusturbenzeri bir fonksiyon yaz, iki farklı sayaç oluşturup birbirinden bağımsız çalıştıklarını kanıtla. - [ ] Bir "çarpan üretici" fonksiyon yaz (
carpanOlusturgibi), 3 farklı çarpanla 3 farklı fonksiyon üret ve hepsini test et. - [ ] Bir listeye closure içeren 5 farklı anonim fonksiyon ekleyen bir döngü yaz (yukarıdaki örneğe benzer), hepsini çalıştırıp doğru değerleri yakaladıklarını doğrula.
- [ ] Dışarıdaki bir listeye, her çağrıda yeni bir eleman ekleyen bir closure fonksiyonu yaz (örn.
logEklefonksiyonu, çağrıldıkça dış bir listeye zaman damgası eklesin).
🏁 Bölüm 5'in Beşinci Konusu Tamamlandı!
Fonksiyonların temel yapısından, parametrelere, arrow function'a, birinci sınıf vatandaş olmalarına ve closure'lara kadar geniş bir yolculuk yaptık. Bölüm 5'in son konusu olan recursion (özyineleme) ile bu bölümü tamamlayacağız.
Sıradaki konu: Bölüm 5 — Konu 26: Recursion (Özyineleme)