Sparround

Funksiyalar və closure-lər

Dart-da parametrlərin üç formasi var və onları qarışdırmaq ən çox rast gəlinən sintaksis səhvidir:

  • Positional (məcburi): void log(String msg, int level) {} — sıra ilə ötürülür.
  • Optional positional — kvadrat mötərizə: void log(String msg, [int level = 0]) {} — buraxıla bilər, default dəyər verilə bilər.
  • Named — fiqurlu mötərizə: void log({required String msg, int level = 0}) {} — çağırışda ad yazılır: log(msg: 'salam').

Qaydalar: []{} eyni imzada birlikdə işlənə bilməz; null safety-dən sonra default dəyəri olmayan non-nullable named parametr mütləq required olmalıdır; default dəyər həmişə compile-time sabiti olmalıdır (const [] olar, [] olmaz — daha doğrusu, const konteksti tələb olunur).

FormaİmzaÇağırışNə vaxt
Positional`f(int a, int b)``f(1, 2)`1-2 aydın arqument
Optional positional`f(int a, [int b = 0])``f(1)` və ya `f(1, 2)`Nadir; köhnə API-lərdə
Named`f({required int a, int b = 0})``f(a: 1, b: 2)`3+ arqument, bool bayraqlar, konfiq obyektləri

Funksiyalar birinci dərəcəli dəyərlərdir. Funksiyanı dəyişənə mənimsətmək, parametr kimi ötürmək və qaytarmaq olar. Funksiya tipini yazmağın iki yolu var:

  • İnline: void run(int Function(String) parse) {}
  • typedef ilə ad verərək: typedef Parser = int Function(String raw);

typedef uzun callback imzalarını oxunaqlı edir və eyni imza bir neçə yerdə təkrarlananda dəyişikliyi bir nöqtəyə yığır. Anonim funksiya ((x) => x * 2) və arrow sintaksisi (=>) yalnız tək ifadə üçün işləyir — => bloku deyil, ifadəni qaytarır.

Diqqət: Function (böyük hərflə, parametrsiz) faktiki olaraq "hər hansı funksiya" deməkdir və tip yoxlamasını itirir — həmişə imzanı tam yaz: bool Function(User).

Closure — funksiya plus onun yarandığı leksik mühit. Dart-da closure xarici dəyişəni dəyərinə görə deyil, dəyişənin özünə görə tutur: dəyişən sonra dəyişsə, closure yeni dəyəri görür.

Bu, klassik loop-capture sualının əsasıdır. Dart-da for (var i = 0; i < 3; i++) hər iterasiya üçün yeni `i` binding-i yaradır, ona görə toplanan closure-lər 0, 1, 2 çap edir — JavaScript-in var davranışından fərqli olaraq. Amma dövrdən kənarda elan olunmuş dəyişən tək binding-dir və bütün closure-lər son dəyəri görür:

  • for (var i = 0; ...) → 0, 1, 2 (hər iterasiyada yeni binding)
  • var i; for (i = 0; ...) → 3, 3, 3 (tək binding)

Closure-lər həm də yaddaş saxlayır: callback obyekti tutursa, o obyekt GC oluna bilmir. Uzunömürlü listener-lərdə this-i tutan closure yaddaş sızmasının tipik səbəbidir.

Interview ipucu. Loop-capture sualı Dart-da tələ kimi verilir, çünki müsahiblərin çoxu JavaScript cavabını gözləyir. Güclü cavab: "Dart-da `for` dövrünün `var` ilə elan olunan sayğacı hər iterasiya üçün yeni binding alır, ona görə nəticə 0, 1, 2-dir. Əgər dəyişən dövrdən kənarda elan olunubsa, tək binding var və nəticə 3, 3, 3 olur." Sonra əlavə et ki, for-in dövründə də hər element yeni binding-dir.

İkinci tez-tez verilən sual: "Named parametrləri niyə positional-dan üstün tutursan?" — cavabda foo(true, false, true) kimi çağırışın oxunmazlığını, required-in compile-time təhlükəsizliyini və gələcəkdə parametr əlavə etməyin sıraya toxunmadan mümkün olduğunu vurğula.

📚 Mənbələr və sənədlər