Kolleksiyalar və Iterable
Üç əsas kolleksiya: List (sıralı, təkrarlara icazə verir), Set (unikal elementlər, ==/hashCode əsasında), Map (açar-dəyər). Hər üçü default olaraq LinkedHash... implementasiyasıdır, yəni əlavə olunma sırası qorunur.
Literal yazılışlarda tipi açıq göstərmək vərdiş olmalıdır: boş {} — bu, Map-dir, boş Set üçün <String>{} yazılır. Eyni şəkildə boş [] konteksdən tip çıxara bilmirsə dynamic alır — <User>[] yaz.
Kolleksiyaların konstruksiya sintaksisi Dart-ın ən faydalı xüsusiyyətlərindəndir:
- collection-if:
[if (isAdmin) 'delete'] - collection-for:
[for (final u in users) u.name] - spread:
[...base, 'extra'] - null-aware spread:
[...?maybeNull]—nullolsa, sadəcə heç nə əlavə etmir
Bunlar imperativ if/for blokları ilə siyahı yığmaqdan həm qısa, həm də const-a uyğun olduğu üçün üstündür.
| Yaradılış | Nəticə | Nə edilə bilər |
|---|---|---|
| `[1, 2, 3]` | Growable list | `add`, `remove`, `length = n` |
| `List.filled(3, 0)` | Fixed-length list | Element dəyişmək olar, `add` — `UnsupportedError` |
| `List.unmodifiable([1, 2])` | Read-only view | Heç bir mutasiya yoxdur |
| `const [1, 2]` | Canonicalise olunmuş immutable list | Heç bir mutasiya yoxdur |
| `someIterable.toList()` | Yeni growable list | Tam mutasiya |
Iterable laziness — bu mövzunun ən vacib hissəsidir. map, where, expand, take, skip, followedBy dərhal heç nə hesablamır. Onlar lazy `Iterable` qaytarır: kod yalnız iterasiya başlayanda (for-in, toList(), first, length, fold) işə düşür.
Bundan iki nəticə çıxır:
- Yan effektlər gözlənilməz vaxtda baş verir.
users.map((u) => log(u));tək başına heç nə çap etmir — çünki heç kim iterasiya etmir. - Zəncir hər iterasiyada yenidən icra olunur.
final active = users.where(isActive);sonraactive.lengthvəactive.firstyazsan,isActiveiki dəfə işləyəcək. Əgər mənbə siyahı arada dəyişibsə, iki nəticə fərqli ola bilər.
Qayda: nəticəni bir dəfədən çox istifadə edəcəksənsə, `toList()` (və ya `toSet()`) çağır. Əksinə, böyük mənbədən yalnız ilk uyğun elementi axtarırsansa, laziness sənin xeyrinədir — where(...).first bütün siyahını gəzmir.
Əlavə tələ: lazy Iterable-ı iterasiya edərkən mənbə kolleksiyanı dəyişsən, ConcurrentModificationError alırsan.
| Metod | Qaytarır | Lazy? | Tipik istifadə |
|---|---|---|---|
| `map` | `Iterable<R>` | Bəli | Çevirmə |
| `where` | `Iterable<T>` | Bəli | Filtr |
| `expand` | `Iterable<R>` | Bəli | flatMap — iç-içə siyahıları düzləşdirmək |
| `fold` | Tək dəyər | Xeyr | Başlanğıc dəyəri olan aqreqasiya |
| `reduce` | Tək dəyər | Xeyr | Boş olmayan kolleksiyanın aqreqasiyası |
| `any` / `every` | `bool` | Xeyr (short-circuit) | Şərt yoxlaması |
| `toList` / `toSet` | Kolleksiya | Xeyr | Nəticəni materializasiya etmək |
Interview ipucu. "map nə qaytarır?" sualı sadə görünür, amma əsl yoxlama laziness-dir. Güclü cavab: "`Iterable`, `List` yox — və o lazy-dir, yəni funksiya iterasiya başlayana qədər çağırılmır. Nəticəni bir neçə dəfə oxuyacağamsa `toList()` edirəm, çünki əks halda zəncir hər dəfə yenidən icra olunur."
Ən çox edilən səhv: map-i JavaScript-dəki kimi dərhal yeni massiv qaytaran metod saymaq. İkinci səhv: fold və reduce fərqini bilməmək — reduce boş kolleksiyada StateError atır, fold isə başlanğıc dəyəri olduğu üçün təhlükəsizdir və tip dəyişməyə (List<int> → String) imkan verir.
📚 Mənbələr və sənədlər
- Kolleksiyalarrəsmidart.dev
- Iterable kolleksiyalarrəsmidart.dev
Iterable-in tənbəl (lazy) davranışı burada rəsmi olaraq izah olunur.