Sparround

Enhanced enum-lar

Dart 2.17-yə qədər enum sadəcə adlar siyahısı idi. İndi enum tam hüquqlu tipdir: sahələri, const konstruktoru, metodları, getter-ləri ola bilər, interfeys implement edə və mixin qoşa bilər.

Qaydalar:

  • Dəyərlər birinci yazılır, sonra ; qoyulur, sonra qalan üzvlər gəlir.
  • Konstruktor mütləq const olmalıdır və bütün sahələr final — çünki enum dəyərləri compile-time sabitləridir.
  • Enum başqa class-ı extends edə bilməz (implicit olaraq Enum-dan gəlir), amma implementswith mümkündür.
  • Ən azı bir dəyər olmalıdır — boş enum yoxdur.

Bu, praktikada nə deməkdir: əvvəllər switch-lə yazılan "enum → dəyər" xəritələri (kod, rəng, mətn açarı) artıq birbaşa enum-un içində sahə kimi yaşayır.

ÜzvNə qaytarırDiqqət
`Role.values`Bütün dəyərlərin `List` şəklində siyahısı, elan sırasındaDəyişməz siyahıdır; `where`, `map` ilə sərbəst işlətmək olar
`role.name`Dəyərin adı `String` kimi — `'admin'``toString()` isə `'Role.admin'` verir — serializasiyada `name` istifadə et
`role.index`0-dan başlayan sıra nömrəsiBazaya yazma! Dəyərlərin sırası dəyişəndə köhnə data korlanır
`Role.values.byName('admin')`Ada görə dəyəri tapırTapılmasa **ArgumentError atır** — xarici datanı birbaşa vermə
`Role.values.asNameMap()``Map<String, Role>` — təhlükəsiz axtarış üçün`asNameMap()[raw]` `null` qaytarır, atmır
`compareTo`Default olaraq `index`-ə görə müqayisə (`Enum` `Comparable` deyil, amma `EnumX` genişləndirmələri var)Məntiqi sıralama lazımdırsa `Comparable` implement et

Enum üzərində exhaustive switch. Enum-un dəyər çoxluğu bağlıdır, ona görə kompilyator switch-i tam yoxlayır: bütün dəyərləri əhatə etsən default lazım deyil. Yeni dəyər əlavə edən kimi default-suz switch-lər kompilyasiya olunmur — bu, sealed class ilə eyni faydadır və enum-un ən güclü tərəfidir.

Buna görə praktik qayda: enum üzərində `default` yazma. default exhaustiveness yoxlamasını söndürür və "yeni statusu emal etməyi unutduq" bug-u səssizcə runtime-a keçir.

switch ifadəsi (expression) formasını üstün tut — o, dəyər qaytarır və hər şaxənin nəyisə qaytarmasını məcbur edir:

  • String label(Role r) => switch (r) { Role.admin => 'Admin', ... };

Enum, yoxsa sealed class? Bu, artıq standart müsahibə sualıdır. Fərqi bir cümləyə yığmaq olar: enum sabit dəyərlər çoxluğudur, sealed hierarchy isə fərqli formalı variantlar çoxluğudur.

Seçim meyarları:

  • Hər variantın öz datası varmı? CardPayment(last4)CashPayment() fərqli sahələr daşıyır → sealed. Enum-da bütün dəyərlər eyni sahə dəstini paylaşır.
  • Variant sayı runtime-da genişlənməlidirmi? İkisi də yox — hər ikisi bağlıdır.
  • Sadəcə adlar siyahısıdırsa (Role, Direction, LogLevel) → enum. Daha sadə, values pulsuz gəlir, serializasiya asandır.
  • Hər variant üçün fərqli davranış lazımdırsa, hər ikisi işləyir: enum-da metod, sealed-də override.

Əlavə praktik arqument: enum values, byNameindex ilə hazır serializasiya verir; sealed hierarchy üçün bunu özün yazmalısan. Əvəzində sealed generic ola bilir (Result<T>) və enum ola bilmir.

Müsahibə ipucu. İki tələ var, ikisi də praktikadan gəlir.

Birincisi: "enum dəyərini bazaya necə yazarsan?" Zəif cavab index-dir. Güclü cavab: `index` heç vaxt persist edilmir — kimsə dəyərləri əlifba sırası ilə düzəldən kimi bütün köhnə data səhv oxunur. name (və ya enum-un içindəki açıq code sahəsi) yazılır və oxuyanda asNameMap() ilə təhlükəsiz parse edilir.

İkincisi: "`byName` ilə server datasını parse etmək olar?" — Xeyr, byName tapmayanda ArgumentError atır. Doğru yanaşma Role.values.asNameMap()[raw] ?? Role.unknown və ya firstWhere(..., orElse: ...) — və enum-a qəsdən unknown dəyəri əlavə etmək. Bu cavab səni "dili bilən"dən "prod-da işləyən" səviyyəyə keçirir.

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