Sparround

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ş verirDü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 susdurmaqKompilyasiya 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ırBir 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 etmirKonstruktorda 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şənLokal ad sahəni gizlədir — kod düz görünür, amma heç nəyi dəyişmirAdları 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ərMəzmun üçün həmişə `==`; `identical` yalnız cache/canonicalization məsələlərində
`await`-dən sonra ölmüş obyektə toxunmaqAsync iş obyektin ömründən uzun sürür: `Bad state: ... after dispose` və ya səssiz sızmaHə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ı pozurMinor 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);fetchName iki dəfə (əslində length üçün hamısı, sonra first üçün bir dəfə də) çağırılır.
  • f yan 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_callsalways_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