Klassik Dart tələləri
Bu mövzu "bilik" deyil, refleks haqqındadır. İnterview-da sənə çox vaxt 15 sətirlik kod göstərib "burada nə səhvdir?" soruşurlar — və qiymətləndirilən şey nə qədər sürətlə və nə qədər sistemli baxdığındır.
Faydalı vərdiş: koda həmişə eyni ardıcıllıqla bax:
1. await hər asinxron çağırışın qarşısındadırmı?
2. Null-a münasibət: ! işarəsi var? Onun əsası nədir?
3. Kolleksiya: iterasiya zamanı dəyişdirilirmi? == ilə müqayisə olunurmu? Iterable neçə dəfə keçilir?
4. Ədədlər: / yoxsa ~/? Pul double-dadırmı?
5. Ömür: await-dən sonra obyekt hələ də canlıdırmı?
Aşağıdakı cədvəl həmin siyahının genişlənmiş halıdır — hər sətir real kod review-larda dəfələrlə rast gəlinən haldır.
| Tələ | Nə baş verir | Düzgün variant |
|---|---|---|
| Unudulmuş `await` (fire-and-forget) | Funksiya iş bitmədən qayıdır; xəta `try/catch`-dən yan keçir və unhandled olur | `await repo.save(x);` — qəsdən olarsa `unawaited(...)` + `catchError`; lint: `unawaited_futures` |
| `!` ilə analyzer-i susdurmaq | Kompilyasiya xətası runtime `Null check operator used on a null value`-ya çevrilir | `?.`, `??`, `if (x != null)` promotion, və ya `late final` — `!` yalnız sübut edilə bilən halda |
| İterasiya zamanı siyahını dəyişmək | `ConcurrentModificationError` — həm də yalnız bəzi datalarda üzə çıxa bilər | `list.removeWhere(...)` və ya `for (final x in [...list])` (kopya üzərində) |
| Kolleksiyaları `==` ilə müqayisə etmək | `[1, 2] == [1, 2]` → `false`: `List` üçün `==` identiklikdir, dərin bərabərlik deyil | `const DeepCollectionEquality().equals(a, b)` (package:collection); Flutter-də `listEquals`/`mapEquals` |
| Lazy `Iterable`-i iki dəfə keçmək | `map`/`where` hər keçiddə yenidən hesablanır — iş iki dəfə görülür, yan effektlər təkrarlanır | Bir dəfə materiallaşdır: `.toList()` / `.toSet()` |
| `int` bölməsində `/` işlətmək | `7 / 2` → `3.5` (`double`), `List` indeksi kimi işlətsən tip xətası | Tam bölmə üçün `7 ~/ 2` → `3`; pulu minor vahiddə `int` saxla |
| `late` ilə "sonra doldurarıq" | Oxunma yazılmadan əvvəl olarsa, `LateInitializationError` — kompilyator artıq kömək etmir | Konstruktorda təyin et, ya nullable saxla; `late` yalnız lazy hesablama və dövri asılılıq üçün |
| Closure-da kölgələnmiş dəyişən | Lokal ad sahəni gizlədir — kod düz görünür, amma heç nəyi dəyişmir | Adları fərqləndir və ya `this.count` ilə açıq yaz; `dart analyze` bəzi halları tutur |
| `==` ilə `identical` qarışdırmaq | `==` dəyəri, `identical` isə eyni obyekt olub-olmadığını yoxlayır; string-lər üçün nəticələr fərqlənə bilər | Məzmun üçün həmişə `==`; `identical` yalnız cache/canonicalization məsələlərində |
| `await`-dən sonra ölmüş obyektə toxunmaq | Async iş obyektin ömründən uzun sürür: `Bad state: ... after dispose` və ya səssiz sızma | Hər `await`-dən sonra `if (_disposed) return;`; `dispose()`-da subscription və timer-ləri ləğv et |
| `double` ilə pul hesablamaq | `0.1 + 0.2 != 0.3`; qəpiklər yığılıb hesabatı pozur | Minor vahiddə `int` (qəpik) və ya `Decimal` paketi; formatlaşdırma yalnız göstərmə anında |
| `dynamic` ilə tipi "aşmaq" | Bütün yoxlamalar runtime-a keçir; `json['user']['name']` bir gün `NoSuchMethodError` verir | `Object?` + pattern matching və ya model sinfinə parse; lint: `avoid_dynamic_calls` |
İki tələ xüsusi izah istəyir, çünki hər ikisi səssizcə işləyir — kod partlamır, sadəcə səhv nəticə verir.
Lazy `Iterable`. list.map(f) heç nə hesablamır; o, sadəcə "necə hesablanacağını" bilən obyekt qaytarır. Hər dəfə onu keçəndə f yenidən çağırılır. Ona görə:
final r = ids.map(fetchName); print(r.length); print(r.first);—fetchNameiki dəfə (əslindəlengthüçün hamısı, sonrafirstüçün bir dəfə də) çağırılır.fyan effektlidirsə (log, sayğac, şəbəkə), effekt təkrarlanır.- Nəticəni bir neçə dəfə istifadə edəcəksənsə, dərhal
.toList()yaz. Əksinə, böyük siyahını bir dəfə keçirsənsə, lazy qalması yaddaşa qənaətdir.
Kolleksiya bərabərliyi. Dart-da List, Map, Set üçün == identiklikdir. Buna görə [1, 2] == [1, 2] yalandır, amma expect(a, equals(b)) testdə işləyir (matcher elementbəelement müqayisə edir) — bu uyğunsuzluq çox adamı çaşdırır.
Dərin müqayisə üçün package:collection-dan DeepCollectionEquality, sadə siyahılar üçün Flutter-in listEquals funksiyası istifadə olunur. Öz sinfində == override edirsənsə, hashCode-u da mütləq override et — və kolleksiya sahəsi varsa, Object.hashAll(items) işlət. Bu qaydanı pozan sinif Set-də dublikat kimi görünür və Map açarı kimi tapılmır.
Interview tövsiyəsi: "Bu kodda nə səhvdir?" tapşırığında skan ardıcıllığını səsli söylə: "Əvvəlcə async-ə baxıram... burada await yoxdur. Sonra null-a... ! var və əsası görünmür. Sonra kolleksiyaya..." Beləcə bir səhvi qaçırsan belə, intervyuer sənin sistemli düşündüyünü görür — bu, tapılan səhvlərin sayından daha çox dəyər verilən şeydir. Sonda mütləq profilaktikanı əlavə et: "bunların yarısını unawaited_futures, avoid_dynamic_calls və always_declare_return_types lint qaydaları CI-da tutur" — bu cümlə səni kod yazan namizəddən komanda üçün düşünən namizədə çevirir.
📚 Mənbələr və sənədlər
- Effective Dart: Usagerəsmidart.dev