Dart enum, sınırlı sayıdaki geçerli değeri derleyicinin tanıdığı bir tipe dönüştürür. Flutter durum modellerinde, API yanıtlarında ve kullanıcı akışlarında metin sabitleri yerine enum kullanmak geçersiz değerleri çalışma zamanından önce, derleme sırasında görünür kılar.
Aşağıda temel enum tanımı, Dart 3 ile gelen switch expression ve kapsayıcılık (exhaustiveness) denetimi, Dart 2.17’deki enhanced enum, Dart 3.10’daki nokta kısaltmaları (dot shorthands), enum değerlerini kalıcı olarak saklarken dikkat edilecekler ve enum ile sealed class arasındaki seçim ele alınıyor.
Metin sabitleri yerine neden enum?
if (status == "loading") gibi bir karşılaştırma yazım hatasına ve büyük/küçük harf farkına açıktır. "sucess" yazıldığında derleyici bir şey söylemez; hata ancak o kod yolu çalıştığında ortaya çıkar. Hangi değerlerin geçerli olduğu da kodun içinde dağınık kalır.
Enum, kabul edilen değer kümesini tek bir yerde tanımlar. Derleyici bu kümenin dışındaki bir değere izin vermez, IDE tüm seçenekleri otomatik tamamlamada gösterir ve bir değerin adını değiştirmek, IDE’nin yeniden adlandırma aracıyla tüm kullanım noktalarına güvenle yayılır.
Temel kullanım ve switch expression
enum Status { idle, loading, success, error }
String label(Status status) => switch (status) {
Status.idle => 'Bekliyor',
Status.loading => 'Yükleniyor',
Status.success => 'Tamamlandı',
Status.error => 'Hata oluştu',
};
void main() {
final current = Status.loading;
print(label(current)); // Yükleniyor
}
Switch expression Dart 3.0 ile geldi. Her dal tek bir ifadedir, case anahtar sözcüğü ve break kullanılmaz ve sonuç doğrudan bir değer olarak döner. Yan etkisiz, değer üreten bu biçim fonksiyonel programlamadaki ifade odaklı yaklaşıma yakındır.
Kapsayıcılık denetimi enum’un asıl kazancıdır. Dil sürümü 3.0 ve sonrası olan bir pakette, enum üzerinde yapılan bir switch bir değeri karşılamıyorsa derleme hatası alınır. Bu kural switch statement için de geçerlidir. Dart 3 öncesinde eksik enum dalı yalnız bir uyarıydı. Dart 3’te switch statement içindeki dolu bir case bitince akış switch’in sonuna geçer; bu yüzden eski örneklerdeki break satırlarına artık gerek yoktur.
Bir default ya da _ dalı eklemek switch’i her durumda kapsayıcı yapar. Bunun bedeli şudur: enum’a yeni bir değer eklendiğinde derleyici bu switch’i göstermez. Değerlerin tamamını tek tek yazmak, yeni bir durumun unutulmasını derleme aşamasında yakalar.
Enhanced enum (Dart 2.17+)
Dart 2.17 ile enum’lar alan, yapıcı ve metot taşıyabilir hâle geldi. Her değer, bir const yapıcıyla oluşturulan sabit bir nesnedir:
enum PaymentMethod {
cash(label: 'Nakit', feePercent: 0),
creditCard(label: 'Kredi kartı', feePercent: 2.5),
bankTransfer(label: 'Havale', feePercent: 1.0);
const PaymentMethod({required this.label, required this.feePercent});
final String label;
final double feePercent;
// Komisyon dahil toplam tutar
double totalFor(double amount) => amount + amount * feePercent / 100;
}
void main() {
final method = PaymentMethod.creditCard;
print('${method.label}: ${method.totalFor(100)}'); // Kredi kartı: 102.5
}
Enhanced enum’ların kuralları:
- Değerler gövdenin başında tanımlanır ve en az bir değer olmalıdır.
- Örnek alanları
final, üretici (generative) yapıcılarconstolmalıdır. - Enum başka bir sınıfı genişletemez, çünkü otomatik olarak
Enumsınıfını genişletir; arayüz uygulayabilir ve mixin kullanabilir. index,hashCodeve==ezilemez;valuesadında bir üye tanımlanamaz.
Enum’a sonradan davranış eklemenin bir yolu da extension method yazmaktır. Davranış enum’un kendi sorumluluğundaysa enhanced enum, yalnız belirli bir katmanda (örneğin arayüzde) gerekiyorsa extension daha temiz bir ayrım sağlar.
Dart 3.10 ile nokta kısaltmaları
12 Kasım 2025’te yayımlanan Dart 3.10, bağlamdan tipin anlaşılabildiği yerlerde enum adını yazmadan değere erişmeyi sağlayan nokta kısaltmalarını (dot shorthands) getirdi. Kullanmak için pubspec.yaml içindeki SDK kısıtının alt sınırı en az 3.10 olmalıdır (sdk: ^3.10.0):
enum Status { idle, loading, success, error }
String label(Status status) => switch (status) {
.idle => 'Bekliyor',
.loading => 'Yükleniyor',
.success => 'Tamamlandı',
.error => 'Hata oluştu',
};
void main() {
Status current = .loading; // Status.loading yerine
print(current == .loading); // true
}
Kısaltma yalnız beklenen tip belli olduğunda çözülür. Karşılaştırmada kısaltma == ve != işlecinin sağ tarafında olmalıdır; .loading == current derlenmez. var ile tanımlanan bir değişkende de bağlam tipi olmadığından .loading tek başına kullanılamaz.
values, name, index ve byName
enum Status { idle, loading, success, error }
void main() {
final List<Status> all = Status.values; // tanım sırasıyla tüm değerler
print(all.length); // 4
print(Status.loading.name); // loading
print(Status.loading.index); // 1
print(Status.values.byName('success')); // Status.success
}
Status.values: Tüm değerleri tanım sırasıyla veren birList<Status>. Bir açılır menüyü (dropdown) doldurmak için uygundur.name: Değerin kaynak koddaki adı ('loading').index: Değerin tanım sırasındaki sıfır tabanlı konumu.values.byName(...): Adı verilen değeri bulur; eşleşme yoksaArgumentErroratar.
Enum değerini veritabanında ve API’de saklamak
index değerini veritabanına ya da bir API yanıtına yazmak risklidir. Enum’un ortasına yeni bir değer eklemek veya sırayı değiştirmek, daha önce kaydedilmiş sayıların anlamını sessizce değiştirir: dün 2 “success” demekken bugün başka bir durumu gösterebilir.
name saklamak bu sorunu çözer, ama değerin adını değiştirmek kayıtlı veriyi bu kez de bozar. Kalıcı veride en dayanıklı seçenek, enum’a sırasından ve adından bağımsız, açık bir kod alanı vermektir:
enum OrderStatus {
pending('P'),
shipped('S'),
delivered('D');
const OrderStatus(this.code);
// Veritabanına yazılan kalıcı kod; değiştirilmez
final String code;
// Bilinmeyen kodda null döner; çağıran taraf karar verir
static OrderStatus? tryParse(String code) {
for (final status in values) {
if (status.code == code) return status;
}
return null;
}
}
void main() {
print(OrderStatus.shipped.code); // S
print(OrderStatus.tryParse('D')); // OrderStatus.delivered
print(OrderStatus.tryParse('X')); // null
}
Dışarıdan gelen veride (API yanıtı, eski kayıtlar) bilinmeyen bir değer her zaman olasıdır. byName bu durumda istisna attığı için güvenilmeyen girdide yukarıdaki gibi null döndüren bir arama yapmak ve bilinmeyen değeri açıkça ele almak daha güvenlidir.
Gerçek dünyada kullanım
- Ağ ve yükleme durumları:
idle,loading,success,errorgibi yalnız etiket taşıyan durumlar. - Tema seçimi: Flutter’daki
ThemeMode(system,light,dark) zaten bir enum’dır. Uygulamaya özel tema seçenekleri de aynı şekilde modellenebilir. - Rota ve sekme adları: Sabit bir ekran listesini enum ile tanımlamak, yazım hatasıyla yanlış rotaya gitmeyi derleme aşamasında engeller.
- Doğrulama hata türleri:
required,tooShort,invalidFormatgibi hata türleri enum olabilir; her türe uygun mesaj switch expression ile seçilir.
Ortak nokta, her durumun yalnız bir etiket olmasıdır. Durumlar farklı veri taşımaya başladığında (hata mesajı, yüklenen liste) enum yetersiz kalır.
Enum mı, sealed class mı?
Dart 3.0 ile gelen sealed sınıf düzenleyicisi, alt tipleri aynı kütüphanede tanımlanmış kapalı bir hiyerarşi kurar. Derleyici tüm alt tipleri bildiği için switch üzerinde enum’daki gibi kapsayıcılık denetimi yapar; fark şudur: her alt tip kendi verisini taşıyabilir.
sealed class LoadState {}
class Loading extends LoadState {}
class Loaded extends LoadState {
Loaded(this.items);
final List<String> items;
}
class Failed extends LoadState {
Failed(this.message);
final String message;
}
String describe(LoadState state) => switch (state) {
Loading() => 'Yükleniyor',
Loaded(:final items) => '${items.length} kayıt yüklendi',
Failed(:final message) => 'Hata: $message',
};
Enhanced enum’da her değerin alanları sabittir ve tüm değerler aynı alanları paylaşır. Çalışma anında değişen, duruma özgü veri gerekiyorsa sealed class doğru araçtır. Yalnız etiket, ya da tanım anında sabitlenebilen veri yetiyorsa enum daha kısa ve okunaklıdır.
Sonuç
Bir değer gerçekten kapalı bir seçenek kümesine sahipse enum, metin sabitlerinden daha açık ve güvenli bir model sunar; Dart 3 ile switch üzerindeki kapsayıcılık denetimi bu güvenceyi derleme hatasına dönüştürür. Değerleri kalıcı olarak saklarken index yerine açık bir kod alanı kullanın. Her durum farklı veri taşıyorsa sealed class daha uygundur; seçimi alışkanlığa göre değil, durumların veri ve davranış gereksinimine göre yapın.