Flutter ve Dart 3: Records, Patterns ve İleri Düzey Mülakat Soruları

Dart 3 records, pattern matching ve sealed class yapıları Flutter kod örnekleriyle açıklanmaktadır. Kapsamlı eşleştirme, durum modelleme ve teknik mülakat soruları.

Flutter geliştirme için Dart 3 records patterns ve sealed classes

Dart 3, Flutter geliştirme ekosisteminde köklü bir dönüşüm başlatmıştır. Records, pattern matching ve sealed class'lar olmak üzere üç temel yenilik, veri yapılandırma, durum yönetimi ve derleme zamanı güvenliğini kökten değiştirmektedir. Bu özellikler yalnızca sözdizimsel kolaylık sağlamakla kalmayıp, kodun nasıl yapılandırıldığını ve hataların nasıl önlendiği konusunda yeni bir paradigma sunmaktadır. Flutter teknik mülakatlarına hazırlanan geliştiriciler için bu kavramlara hakimiyet, artık belirleyici bir farklılaşma kriteridir.

Temel Kavramlar

Dart 3, records (yapısal veri tipleri), kapsamlı pattern matching ve sealed class'lar sunmaktadır. Bu üç mekanizma bir arada kullanıldığında, derleyici tarafından garanti edilen tip güvenliği ile karmaşık durumların modellenmesini mümkün kılar — üçüncü parti kütüphanelere ihtiyaç duymadan.

Records: Hafif Yapısal Veri Tipleri

Dart 3 öncesinde bir fonksiyondan birden fazla değer döndürmenin yolu, özel bir sınıf oluşturmak, bir Map kullanmak veya harici bir kütüphaneden Tuple almaktı. Records bu sorunu doğal bir şekilde çözmektedir. Bir record, anonim, değiştirilemez ve yapısal eşitliğe sahip bir tip olup, konumsal veya adlandırılmış alanlar içerebilir.

Konumsal record'lar, sıralamanın her değeri tanımlamaya yettiği basit dönüşler için uygundur. Daha karmaşık yapılar için adlandırılmış alanlar, okunabilirliği önemli ölçüde artırmakta ve parametre ters çevirme hatalarını önlemektedir.

user_repository.dartdart
// Returning multiple values with a positional record
(String, int) parseUserInput(String raw) {
  final parts = raw.split(':');
  return (parts[0].trim(), int.parse(parts[1]));
}

// Named fields improve readability for complex returns
({String name, String email, bool isVerified}) fetchUserProfile(String id) {
  // Simulated database lookup
  return (
    name: 'Alice Chen',
    email: 'alice@example.com',
    isVerified: true,
  );
}

Record'ların en temel özelliklerinden biri yapısal eşitliktir. Aynı değerleri içeren iki record, == operatörünün özel olarak tanımlanmasına veya equatable gibi bir paketin kullanılmasına gerek kalmadan birbirine eşittir. Bu özellik, birim testlerini ve durum karşılaştırmalarını büyük ölçüde basitleştirmektedir.

records_equality.dartdart
// Structural equality — no need for custom == operator
void main() {
  final a = (1, 'hello');
  final b = (1, 'hello');
  print(a == b); // true — records compare by value

  // Named fields also support equality
  final profile1 = (name: 'Alice', role: 'admin');
  final profile2 = (name: 'Alice', role: 'admin');
  print(profile1 == profile2); // true
}
Record'lar Sınıf Değildir

Record'ların nesne kimliği yoktur. Bunlara metot eklemek, arayüz uygulamak veya kalıtım yoluyla genişletmek mümkün değildir. İş mantığı verilere eşlik etmesi gerekiyorsa, sınıf doğru araçtır. Record'lar veri taşımak için tasarlanmıştır; davranış kapsülleme için değil.

Pattern Matching: Ayrıştırma ile Kodda Netlik

Dart 3'ün pattern matching özelliği, basit ayrıştırmanın çok ötesine geçmektedir. Değer çıkartma, tip doğrulama ve koruma koşullarının uygulanmasını, derleme zamanında doğrulanan bildirimsel bir sözdizimi içinde birleştirir.

Record ayrıştırması, kodda tekrarlanan indeks veya alan adı erişimlerini ortadan kaldırır. Rest operatörü (...) ile liste pattern'ları, bir koleksiyonun ilk elemanlarının zarif bir şekilde çıkarılmasını sağlar.

pattern_basics.dartdart
// Destructuring a record with pattern matching
void main() {
  final (name, email, isVerified) = fetchUserProfile('u-123');
  // name, email, isVerified are now local variables

  // List patterns with rest operator
  final scores = [98, 87, 92, 76, 84];
  final [first, second, ...remaining] = scores;
  print('Top two: $first, $second'); // 98, 87
  print('Others: $remaining');        // [92, 76, 84]
}

Dart 3'ün switch ifadeleri, geleneksel switch yapılarında önemli bir evrim noktasıdır. Bir değer döndürür, when ile koruma koşullarını destekler ve nesne tipleri üzerinde pattern matching uygulayabilir. Derleyici, tüm durumların kapsandığını doğrular ve bu sayede işlenmemiş durumlardan kaynaklanan bir hata kategorisini tamamen ortadan kaldırır.

pattern_switch.dartdart
// Switch expression with guard clauses
String classifyScore(int score) => switch (score) {
  >= 90 => 'Excellent',
  >= 80 => 'Good',
  >= 70 => 'Average',
  >= 60 => 'Below Average',
  _ => 'Needs Improvement',
};

// Object pattern matching with type checking
String describeValue(Object value) => switch (value) {
  int n when n < 0   => 'Negative integer: $n',
  int n              => 'Positive integer: $n',
  String s when s.isEmpty => 'Empty string',
  String s           => 'String of length ${s.length}',
  List l when l.isEmpty  => 'Empty list',
  List l             => 'List with ${l.length} elements',
  _                  => 'Unknown type',
};

Bu switch ifadeleri, özellikle Flutter uygulamalarında durum yönetimi ve widget oluşturma bağlamında, if-else zincirlerinin yerine birçok durumda avantajlı bir alternatif sunmaktadır.

Sealed Class'lar: Derleyici Tarafından Garanti Edilen Kapsamlılık

Sealed class'lar, kapalı bir alt tip kümesi tanımlar. Derleyici mümkün olan tüm varyantların tamamını bilir ve bu sayede her switch ifadesinin bütün durumları kapsadığını doğrulayabilir. Atlanan bir alt tip, üretimdeki bir hata yerine derleme hatasına dönüşür.

Bu mekanizma, bir uygulamanın durumlarının modellenmesine özellikle uygundur. Aşağıdaki örnek, bir kimlik doğrulama akışının olası dört durumunu tanımlamaktadır.

auth_state.dartdart
// Sealed class defining all possible authentication states
sealed class AuthState {}

class AuthInitial extends AuthState {}

class AuthLoading extends AuthState {}

class AuthAuthenticated extends AuthState {
  final String userId;
  final String displayName;
  AuthAuthenticated({required this.userId, required this.displayName});
}

class AuthError extends AuthState {
  final String message;
  final int? statusCode;
  AuthError({required this.message, this.statusCode});
}

Bir widget bu durumu tükettiğinde, kapsamlı switch yapısı her varyantın ele alındığını garanti eder. Sonradan beşinci bir durum eklendiğinde (örneğin AuthMfaRequired), derleyici kodda güncellenmesi gereken tüm noktaları anında işaret eder.

auth_widget.dartdart
// Exhaustive switch — compiler error if a case is missing
Widget buildAuthUI(AuthState state) => switch (state) {
  AuthInitial()       => const LoginPrompt(),
  AuthLoading()       => const CircularProgressIndicator(),
  AuthAuthenticated(
    displayName: final name
  )                   => Text('Welcome, $name'),
  AuthError(
    message: final msg,
    statusCode: final code,
  )                   => ErrorBanner(
    message: msg,
    code: code,
  ),
};

Sealed class ve kapsamlı switch kombinasyonu, default veya genel _ dallarının kullanılma ihtiyacını ortadan kaldırır. Her yürütme yolu açıkça tanımlanmıştır ve bu durum hem bakım kolaylığı hem de kodun dokümantasyon işlevi görmesi açısından önemli bir kazanım sağlar.

Records, Patterns ve Sealed Class'ların Birlikte Kullanımı

Dart 3'ün gerçek gücü, bu üç özelliğin birlikte kullanıldığında ortaya çıkar. Genel amaçlı bir sonuç tipi olarak sealed class, hem başarı verilerini (record formunda metadata ile) hem de hataları kapsülleyebilir.

api_result.dartdart
// Generic sealed result type for API operations
sealed class ApiResult<T> {}

class ApiSuccess<T> extends ApiResult<T> {
  final T data;
  final ({int statusCode, Map<String, String> headers}) metadata;
  ApiSuccess(this.data, {required this.metadata});
}

class ApiFailure<T> extends ApiResult<T> {
  final String error;
  final int? statusCode;
  ApiFailure(this.error, {this.statusCode});
}

Widget tarafında pattern matching, her durum ve veri kombinasyonunun hassas bir şekilde ele alınmasını sağlar. İç içe geçmiş pattern'lar record'dan metadata'yı çıkarırken HTTP koduna göre filtreleme yapar ve koruma koşulları boş listeler ile dolu listeleri birbirinden ayırır.

product_screen.dartdart
// Consuming the sealed result with pattern matching
Widget buildProductList(ApiResult<List<Product>> result) => switch (result) {
  ApiSuccess(
    data: final products,
    metadata: (statusCode: 200, headers: _),
  ) when products.isNotEmpty => ListView.builder(
    itemCount: products.length,
    itemBuilder: (_, i) => ProductCard(products[i]),
  ),
  ApiSuccess(data: final products) when products.isEmpty =>
    const EmptyState(message: 'No products found'),
  ApiFailure(statusCode: 401) =>
    const AuthExpiredBanner(),
  ApiFailure(error: final msg) =>
    ErrorDisplay(message: msg),
};

Bu desen, manuel tip kontrollerini, cast işlemlerini ve test edilmemiş else dallarını tamamen ortadan kaldırır. Her yürütme yolu tiplendirilmiş ve derleme zamanında doğrulanmıştır.

Pattern matching aynı zamanda JSON yapılarından güvenli veri çıkarma için de etkili bir araçtır — API yanıtlarının işlenmesinde sıkça karşılaşılan bir senaryo.

null_pattern.dartdart
// If-case for null-safe extraction
void processUser(Map<String, dynamic> json) {
  if (json case {'name': String name, 'age': int age}) {
    // name and age are non-nullable here
    print('$name is $age years old');
  } else {
    print('Invalid user data');
  }
}

if-case yapısı, anahtarların varlığını, tiplerini ve değer çıkarımını eş zamanlı olarak gerçekleştirir. Bu pattern, containsKey zincirlerinin ve manuel cast işlemlerinin yerine geçmektedir.

Flutter mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

İleri Düzey Teknik Mülakat Soruları

Aşağıdaki sorular, Dart 3'ün derinlemesine anlaşılmasını değerlendirmek amacıyla Flutter teknik mülakatlarında düzenli olarak sorulmaktadır.

S: Dart 3'te record ile sınıf arasındaki temel fark nedir?

Record, yapısal eşitliğe sahip anonim ve doğası gereği değiştirilemez bir tiptir. Aynı değerlere sahip iki record birbirine eşittir. Sınıf ise nesne kimliğine sahiptir: aynı değerlere sahip iki örnek, == ve hashCode açıkça tanımlanmadığı sürece varsayılan olarak eşit değildir. Record'lara metot eklemek, arayüz uygulamak veya kalıtım yoluyla genişletmek mümkün değildir. Veri taşıma ve çoklu değer dönüşü için record, kapsüllü iş mantığı için sınıf tercih edilmelidir.

S: Durum yönetiminde sealed class'lar neden enum'lardan daha uygundur?

Enum'lar her varianta özel veri taşımasına izin vermez. Enum olarak tanımlanan bir AuthState, yalnızca authenticated varyantına ait bir userId iliştiremez. Sealed class'lar, doğrulama kapsamlılığını (enum'lardaki gibi) her varianta özel heterojen veri taşıma kapasitesiyle birleştirir. Derleyici, switch ifadelerinde her alt tipin işlendiğini garanti eder.

S: Pattern matching, null safety ile nasıl etkileşir?

Dart 3'ün pattern matching'i, null safety sistemiyle doğal olarak bütünleşir. Tip pattern'ları ile if-case yapısı, bang operatörü (!) kullanılmadan null olmayan değişkenlerin çıkarılmasını garanti eder. Map pattern'ları, anahtarların varlığını ve değerlerinin tipini eş zamanlı olarak doğrulayarak dinamik yapılara güvenli olmayan erişimleri ortadan kaldırır.

S: Switch ifadelerinin switch deyimlerine göre avantajı nedir?

Switch ifadeleri bir değer döndürür, bu da onları atama, fonksiyon dönüşü ve constructor parametresi olarak kullanılabilir kılar. Kapsamlılık zorunluluğu getirir: derleyici kapsanmayan bir durum varsa derlemeyi reddeder. Geleneksel switch deyimleri bu garantilerin hiçbirini sunmaz. Flutter'da switch ifadeleri, her durumun bir widget döndermesi gereken builder desenine özellikle uygundur.

S: Dart 3 record'larının performans üzerindeki etkisi nedir?

Record'lar sınıflar gibi heap üzerinde tahsis edilir, ancak yapısal eşitlikleri karşılaştırmalar için ara nesnelerin tahsis edilmesini önler. Derleyici, küçük boyutlu konumsal record'ları eşdeğer sınıflara kıyasla daha agresif optimize edebilir. Pratikte çoğu kullanım senaryosunda performans etkisi ihmal edilebilir düzeydedir. Temel kazanım, kalıp kodun azaltılması ve okunabilirliğin artmasıdır — bu da hataları azaltır ve geliştirme hızını artırır.

Dart 3'e Geçiş Stratejisi

Mevcut kod tabanlarına sahip ekipler için Dart 3 özelliklerine geçiş kademeli olarak gerçekleştirilebilir. Her şeyi tek seferde dönüştürmek zorunlu değildir.

İlk adım, Map, List<dynamic> veya el yapımı tuple döndüren fonksiyonların tespit edilerek record'larla değiştirilmesidir. Bu yeniden düzenleme yerel kalmakta ve kademeli değişikliklere neden olmamaktadır.

İkinci adım, sonlu durumları modellemek için kullanılan sınıf hiyerarşilerini hedefler. Bilinen alt tip kümesine sahip soyut sınıflar, sealed class'a dönüştürülmek için ideal adaylardır. Bu dönüşüm, işlenmemiş durumların bulunduğu her noktada derleme hataları tetikleyerek eksik dalları ortaya çıkarır.

Üçüncü adım, if-else zincirlerini ve switch deyimlerini pattern matching ile switch ifadelerine dönüştürür. Bu dönüşüm okunabilirliği artırır ve derleyici tarafından kapsamlılık doğrulaması ekler.

Dart 3.10 ve Dot Shorthands

Dart 3.10, bağlamın tipi açıkça belirttiği durumlarda tip adının atlanabilmesini sağlayan dot shorthands sözdizimini sunmaktadır. Örneğin Color color = Color.red yerine Color color = .red yazılabilir. Bu özellik sözdizimsel yükleri daha da azaltmakta ve pattern matching ile doğal bir şekilde bütünleşmektedir.

Sonuç

  • Records, değer bazlı eşitliğe sahip hafif yapısal veri tipleri sunarak çoklu değer dönüşü için gereksiz kalıp sınıflarını ortadan kaldırır
  • Pattern matching, tip doğrulama, koruma koşulları ve derleyici tarafından garanti edilen kapsamlılık ile bildirimsel ayrıştırma sağlar
  • Sealed class'lar kapalı alt tip kümeleri tanımlayarak bir switch ifadesinde bir durumun atlanmasını imkansız kılar
  • Bu üç özelliğin kombinasyonu, karmaşık akışların (kimlik doğrulama, API çağrıları, navigasyon) tam tip güvenliği ile modellenmesini mümkün kılar
  • if-case ile null-safe veri çıkarımı, JSON işleme sırasında manuel anahtar kontrollerini ve güvenli olmayan cast'leri devre dışı bırakır
  • Dart 2'den geçiş kademeli olarak yapılabilir: çoklu değer dönüşleri için record'lar, sonlu durumlar için sealed class'lar, koşullu dallanmalar için switch ifadeleri
  • Bu özellikler Flutter teknik mülakatlarında aktif olarak test edilmektedir — sözdiziminin ötesinde mimari anlayış değerlendirilmektedir

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#flutter
#dart
#pattern-matching
#sealed-classes
#records
#interview

Paylaş

İlgili makaleler