Extension method-lar
Extension — mənbə kodunu dəyişmədən mövcud tipə metod, getter, setter və operator əlavə etməyin yoludur. Dart-ın öz String, int, List tiplərinə də, başqa paketin class-larına da tətbiq oluna bilir.
Elan:
extension StringX on String { bool get isBlank => trim().isEmpty; }- Adsız da yazmaq olar (
extension on String { ... }), amma ad ver — konflikt olandashow/hidevə ya açıq çağırış yalnız adla mümkündür. - Generic ola bilər:
extension ListX<T> on List<T> { T? get firstOrNull => ... } - Nullable tip üzərində də mümkündür:
extension on String? { ... }— bu haldathisnullola bilər.
Extension daxilində this receiver-dir və çox vaxt onu yazmağa ehtiyac qalmır: trim() avtomatik this.trim() deməkdir.
Statik həll — ən sevilən müsahibə tələsi. Extension metodları compile-time-da, dəyişənin statik tipinə görə seçilir. Bu, adi metodlardan prinsipial fərqdir: adi metod runtime-da obyektin real tipinə görə (dynamic dispatch) tapılır.
Nəticələr:
Dog dog = Dog(); dog.speak();→DogX.speak()işləyir.Animal a = dog; a.speak();→ eyni obyekt, ammaAnimalX.speak()işləyir, çünki statik tipAnimal-dır.dynamic d = dog; d.speak();→ runtime xətası:dynamicüzərində extension ümumiyyətlə axtarılmır.- Extension metodu override edilə bilməz — alt class-da eyni adlı extension yazmaq "override" deyil, sadəcə başqa bir extension-dır.
Bir qayda da yadda saxla: tipin öz üzvü həmişə üstündür. String-də length var, sənin extension-dakı length heç vaxt çağırılmayacaq. Extension yalnız tipdə həmin ad yoxdursa işə düşür — buna görə dil komandası String-ə yeni metod əlavə edəndə sənin kodun sınmır, sadəcə davranış dəyişə bilər.
| Sual | Extension method | Adi instansiya metodu |
|---|---|---|
| Nə vaxt seçilir? | Compile-time, statik tipə görə | Runtime, real tipə görə |
| Override oluna bilər? | Xeyr | Bəli |
| `dynamic` üzərində işləyir? | Xeyr — runtime `NoSuchMethodError` | Bəli |
| Private sahəyə çıxışı var? | Yalnız eyni kitabxanadadırsa | Bəli |
| İmport-dan asılıdır? | Bəli — extension scope-da olmalıdır | Xeyr |
| Tipin öz üzvü ilə toqquşanda | Uduzur — tipin üzvü üstündür | Aid deyil |
Konfliktlər. İki import eyni tip üçün eyni adlı extension üzvü gətirirsə, kompilyator qərar verə bilmir və xəta verir. Üç həll yolu var:
import 'b.dart' hide Trimmer;— birini gizlət.import 'b.dart' show Squeezer;— yalnız lazım olanı gətir.- Açıq tətbiq:
Trimmer(' x ').squeeze()— extension adını yazaraq çağır. Bu, import-lardan asılı olmayan, ən dəqiq yoldur və statik tip həllini keçmək üçün də işlədilir:AnimalX(dog).speak().
Extension nə vaxt faydalıdır, nə vaxt zərərlidir?
Faydalıdır: kodun oxunuşunu doğrudan dəyişəndə (19999.azn, '2026-01-01'.toDate(), list.firstOrNull), və ya öz tipinə əlavə etmək istədiyin metodu başqasının paketinə əlavə edə bilmədikdə.
Zərərlidir: gizli xərc gətirəndə (getter-in içində şəbəkə çağırışı və ya ağır hesablama), çox ümumi tiplərə (Object, int) çoxlu ad əlavə edəndə — hər int artıq həmin adı "cavablandırır" və avtokomplit zibillənir, və layihədə eyni ideyanın iki extension-la təkrarlanmasına yol verəndə.
Müsahibə ipucu. Sual demək olar həmişə eyni formada gəlir: "`Animal a = dog; a.speak();` nə çap edəcək?". Doğru cavabın strukturu: (1) "extension-lar compile-time-da, statik tipə görə həll olunur" — bu cümləni birinci de; (2) buna görə AnimalX.speak() işləyir, DogX yox, halbuki obyekt Dog-dur; (3) müqayisə əlavə et: adi metod olsaydı, dynamic dispatch nəticəsində Dog-un versiyası işləyərdi.
Ən çox edilən səhv — extension-ı "class-a metod əlavə etmək" kimi izah etmək. Əslində heç bir şey class-a əlavə olunmur: kompilyator a.speak() çağırışını sadəcə AnimalX.speak(a) şəklində statik funksiya çağırışına çevirir. Bu bir cümlə bütün davranışı izah edir — dynamic üzərində niyə işləmədiyini, niyə override oluna bilmədiyini və niyə import-dan asılı olduğunu.
📚 Mənbələr və sənədlər
- Extension method-larrəsmidart.dev